Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Лабораторная работа по процессам full.doc
Скачиваний:
7
Добавлен:
19.12.2018
Размер:
375.3 Кб
Скачать

10. Завершение процесса

Процесс можно завершить четырьмя способами:

  • входная функция первичного потока возвращает управление (рекомендуемый способ),

  • один из потоков процесса вызывает функцию ExitProcess (нежелательный способ);

  • поток другого процесса вызывает функцию TerminateProcess (тоже нежелательно);

  • все потоки процесса умирают по своей воле (большая редкость).

Рассмотрим только что перечисленные способы завершения процесса, а также, что на самом деле происходит в момент его окончания.

10.1. Возврат управления входной функцией первичного потока

Приложение следует проектировать так, чтобы его процесс завершался только после возврата управления входной функцией первичного потока. Это единственный способ, гарантирующий корректную очистку всех ресурсов, принадлежавших первичному потоку. При зтом:

  • любые С++-объекты, созданные данным потоком, уничтожаются соответствующими деструкторами;

  • система освобождает память, которую занимал стек потока;

  • система устанавливает код завершения процесса (поддерживаемый объектом ядра «процесс») — его и возвращает входная функция;

  • счетчик пользователей данного объекта ядра «процесс» уменьшается на единицу.

10.2. Функция ExitProcess

Процесс завершается, когда один из его потоков вызывает ExitProcess:

VOID ExilProcess(UINT fuExitCode);

Эта функция завершает процесс и заносит в параметр fuExitCode код завершения процесса. Возвращаемого значения у ExitProcess нет, так как результат ее действия — завершение процесса. Если за вызовом этой функции в программе присутствует какой-нибудь код, он никогда не исполняется.

Когда входная функция (WinMain, wWinMain, main или wmain) в программе возвращает управление, оно передастся стартовому коду из библиотеки С/C++, и тот проводит очистку всех ресурсов, выделенных им процессу, а затем обращается к ExitProcess, передавая ей значение, возвращенное входной функцией. Вот почему возврат управления входной функцией первичного потока приводит к завершению всего процесса. При завершении процесса прекращается выполнение и всех других его потоков.

В документации из Platform SDK утверждается, что процесс не завершает ся до тех пор, пока не завершится выполнение всех его потоков. Это, конечно, верно, но тут есть одна тонкость. Стартовый код из библиотеки С/С++ обеспечивает завершение процесса, вызывая ExitProcess после того, как первичный поток приложения возвращается из входной функции. Однако, при вызове из нее функции ExitThread (вместо того чтобы вызвать ExitProcess или просто вернуть управление), произойдет завершение первичного потока, но не самого процесса — если в нем еще выполняется какой-то другой поток (или потоки).

Такой вызов ExitProcess или ExitThread приводит к уничтожению процесса или потока, когда выполнение функции еще не завершилось. Что касается операционной системы, то здесь все в порядке: она корректно очистит все ресурсы, выделенные процессу или потоку. Но в приложении, написанном на С/С++, следует избегать вызова этих функций, так как библиотеке С/С++ скорее всего не удастся провести должную очистку.

Далее приведен код, иллюстрирующий данную ситуацию:

#include <windows.h> #include <stdio.h>

class CSomeObj { public: CSomeObj() { printf("Constructor\r\n"), } ~CSomeObj() { printf("Destructor\r\n"); } };

CSomeObj g_GlobalObj;

void main () { CSomeObj LocalObj; ExitProcess(0); // этого здесь не должно быть

// в конце этой функции компилятор автоматически вставил код // для вызова деструктора LocalObj, но ExitProcess не дает его выполнить }

При его выполнении увидим:

Constructor Constructor

Код конструирует два объекта: глобальный и локальный. Но Вы никогда не увидите строку Destructor С++-объекты не разрушаются должным образом из-за того, что ExitProcess форсирует уничтожение процесса и библиотека С/С++ не получает шанса на очистку.

Не следует никогда вызывать ExitProcess в явном виде. Если убрать из предыдущего примера вызов ExitProcess, программа выведет такие строки:

Constructor Constructor

Destructor Destructor

Простой возврат управления от входной функции первичного потока позволил библиотеке С/С++ провести нужную очистку и корректно разрушить С++-объекты. Все это относится не только к объектам, но и ко многим другим вещам, которые библиотека С/С++ делает для процесса.

Замечание: Явные вызовы ExitProcess и ExitThread — распространенная ошибка, которая мешает правильной очистке ресурсов. В случае ExitThread процесс продолжает работать, но при этом весьма вероятна утечка памяти или других ресурсов.