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

9.7. Параметр ppiProclnfo

Параметр ppiProcInfo указывает на структуру PROCESS_INFORMATION, которую необходимо предварительно создать; ее элементы инициализируются самой функцией CreateProcess. Структура представляет собой следующее:

typedef struct _PROCESS_INFORMATION { HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId; } PROCESS_TNFORMATION;

Создание нового процесса влечет за собой создание объектов ядра «процесс» и «поток» В момент создания система присваивает счетчику каждого объекта начальное значение — единицу, Далее функция CreateProcess (перед самым возвратом управлении) открывает объекты «процесс» и «поток» и заносит их описатели, специфичные для данного процесса, в элементы hProcess и hThread структуры PROCESS_INFORMATION. Когда CreateProcess открывает эти объекты, счетчики каждого из них увеличиваются до двух.

Это означает, что, перед тем как система сможет высвободить из памяти объект «процесс», процесс должен быть завершен (счетчик уменьшен до единицы), а родительский процесс обязан вызвать функцию CloseHandle (и тем самым обнулить счстчик) То же самое относится и к объекту «поток» поток должен быть завершен, а родительский процесс должен закрыть описатель объекта «поток».

Замечание

Не забывайте закрывать описатели дочернего процесса и его первичного потока, иначе, пока не закроете свое приложение, будет происходить утечка ресурсов. Конечно, система высвободит все эти ресурсы после завершения родительского процесса, но хорошо написанная программа должна сама закрывать описатели дочернего процесса и его первичного потока, как только необходимость в них отпадает. Пропуск этой операции — одна из самых частых ошибок.

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

Созданному объекту ядра «процесс» присваивается уникальный идентификатор; ни у каких других объектов этого типа в системе не может быть одинаковых идентификаторов. Это же касается и объектов ядра «поток». Причем идентификаторы процесса и потока тоже разные, и их значения никогда не бывают нулевыми. Завершая свою работу, CreateProcess заносит значения идентификаторов в элементы dwProcessId и dwThreadId структуры PROCESS_INFORMATION Эти идентификаторы просто облегчают определение процессов и потоков в системе; их используют, как правило, лишь cпециализированные утилиты вроде Task Manager.

Подчеркну еще один чрезвычайно важный момент система способна повторно использовать идентификаторы процессов и потоков. Например, при создании процесса система формирует объект «процесс», присваивая ему идентификатор со значением, допустим, 122. Создавая новый объект «процесс», система уже не присвоит ему данный идентификатор. Но после выгрузки из памяти первого объекта следующему cоздаваемому объекту «процесс» может быть присвоен тот же идентификатор — 122.

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

Иногда программе приходится определять свой родительский процесс. Однако родственные связи между процессами существуют лишь на стадии создания дочернего процесса. Непосредственно перед началом исполнения кода в дочернем процессе Windows перестает учитывать его родственные связи. В предыдущих версиях Windows не было функций, которые позволяли бы программе обращаться с запросом к ее родительскому процессу. Но ToolHelp-функции, появившиеся в современных версиях Windows, сделали это возможным. С этой целью можно использовать структуру PROCESSENTRY32: ее элемент th32ParentProcessID возвращает идентификатор «родителя» данного процесса. Тем не менее, если программе нужно взаимодействовать с родительским процессом, от идентификаторов лучше отказаться. Для определения родительского процесса существуют более надежные механизмы: объекты ядра, описатели окон и т. д.

Единственный способ добиться того, чтобы идентификатор процесса или потока не использовался повторно, — не допускать разрушения объекта ядра "процесс" или "поток". Если только что создан новый процесс или поток, то можно просто не закрывать описатели на эти объекты — вот и все. А по окончании операций с идентификатором, вызвать функцию CloseHandle и освободите соответствующие объекты ядра. Однако для дочернего процесса этот способ не годится, если только он не унаследовал описатели объектов ядра от родительского процесса.