Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
os_a_win.doc
Скачиваний:
15
Добавлен:
17.11.2019
Размер:
715.26 Кб
Скачать

Процессы и потоки в Windows Создание процесса

Для управления процессами в ядре Windows используется объект Process (процесс). Создание процесса осуществляется вызовом функции CreateProcess:

BOOL CreateProcess(

LPCTSTR lpApplicationName, // name of executable module

LPTSTR lpCommandLine, // command line string

LPSECURITY_ATTRIBUTES lpProcessAttributes, // SD

LPSECURITY_ATTRIBUTES lpThreadAttributes, // SD

BOOL bInheritHandles, // handle inheritance option

DWORD dwCreationFlags, // creation flags

LPVOID lpEnvironment, // new environment block

LPCTSTR lpCurrentDirectory, // current directory name

LPSTARTUPINFO lpStartupInf, // startup information

LPPROCESS_INFORMATION lpProcessInformation // process information

);

Как можно видеть, эта функция выглядит не совсем традиционно для функций создания объектов ядра. Вызвано это тем, что она, на самом деле, создает не один, а два объекта – процесс и поток (существование в системе процесса без потоков невозможно). Поэтому этой функции передается два различных дескриптора защиты, и возвращаемым значением является не идентификатор созданного процесса, а логическое значение, сообщающее об успехе или не успехе операции. Получить же дескрипторы созданных объектов мы можем из структуры PROCESS_INFORMATION, указатель на которую следует передать последним аргументом нашей функции:

typedef struct _PROCESS_INFORMATION {

HANDLE hProcess;

HANDLE hThread;

DWORD dwProcessId;

DWORD dwThreadId;

} PROCESS_INFORMATION;

Наряду с дескрипторами процесса и потока мы видим в этой структуре и значения идентификаторов dwProcessId и dwThreadId, которые являются общесистемными идентификаторами процесса и потока соответственно. Если бы мы не имели таких идентификаторов, а пользовались бы только процессно-зависимыми дескрипторами, то наладить взаимодействие между процессами в системе было бы очень тяжело.

Еще одной особенностью этой функции является то, что созданные объекты получают при инициализации значение счетчика использования равное 2. Это происходит потому, что объект процесс используется как для работы самого процесса, так и в родительском процессе, получившим значение hProcess после вызова функции CreateProcess. Уничтожение объекта процесс (и поток) в системе может таким образом произойти только после того, как завершится сам процесс (счетчик будет уменьшен на 1) и будет закрыт дескриптор в родительском процессе (счетчик уменьшен еще на 1). Поэтому обязательно нужно закрыть полученные дескрипторы с помощью функции CloseHandle после того, как они станут вам не нужны (их можно использовать для того, чтобы узнавать состояние процесса или код его завершения).

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

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

  • входная функция первичного потока (обычно это main, wmain, WinMain или wWinMain) возвращает управление;

  • один из потоков процесса вызывает функцию ExitProcess;

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

  • все потоки процесса умирают.

Из всего этого многообразия лучшим вариантом является первый. Только этот способ гарантирует, что ваша программа завершилась корректно. Конечно, Windows в любом случае освободит все использованные вашей программой ресурсы, однако при аварийном завершении процесса не будут, например, выполнены деструкторы объектов C++, что может привести к не сохраненным пользовательским данным, не записанным изменениям в конфигурации и так далее. Библиотека C++ (да и любого другого языка) на самом деле выполняет довольно много полезных операций, как перед стартом вашей программы, так и после ее завершения, и не надо мешать ей это делать. Библиотека сама вызовет ExitProcess, когда этому придет время.

Если же все-таки возникла необходимость аварийно завершить процесс, то мы можем воспользоваться функциями ExitProcess или TerminateProcess. Первая из этих функций уничтожает тот процесс, который ее вызвал, а вторая позволяет завершить любой процесс в системе (если конечно к нему есть доступ), указав его дескриптор. Обе функции позволяют установить код возврата процесса. После вызова этих функций наш процесс прекратит свое существование, все системные ресурсы будут освобождены, однако возможности сохранить данные процесс не получит.

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

Заметим, что завершение родительского процесса в Windows не приводит к завершению запущенных им дочерних процессов.

При завершении процесса происходит следующее:

  1. выполнение всех потоков в процессе прекращается;

  2. все открытые процессом объекты USER и GDI уничтожаются, а объекты ядра закрываются;

  3. код возврата процесса меняется со значения STILL_ACTIVE (0x103) на свое значение;

  4. объект ядра «процесс» переходит в свободное (signaled) состояние (про это состояние будет рассказано в разделе про Wait-функции);

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

Если после выполнения этой операции счетчик использования процесса все еще не равен 0 (есть открытые дескрипторы в других процессах), то сам объект ядро не уничтожается. Однако использовать этот объект можно только для того, чтобы обращаться к Wait-функциями или получить код возврата, используя функцию GetExitCodeProcess. После того, как все оставшиеся дескрипторы будут закрыты, Windows уничтожит и сам объект «процесс».

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]