Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Создание эффективных приложений для Windows Джеффри Рихтер 2004 (Книга).pdf
Скачиваний:
377
Добавлен:
15.06.2014
Размер:
8.44 Mб
Скачать

Рис. 5-4. MMC Performance Monitor счетчики, относящиеся к отдельным параметрам задания

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

Уведомления заданий

Итак, базовые сведения об объектах-заданиях я изложил. Единственное, что осталось рассмотреть, — уведомления Допустим, Вам нужно знать, когда завершаются все про цессы в задании или заканчивается все отпущенное им процессорное время. Либо выяснить, когда в задании порождается или уничтожается очередной процесс Если такие уведомления Вас не интересуют (а во многих приложениях они и не нужны), работать с заданиями будет очень легко — не сложнее, чем я уже рассказывал. Но если они все же понадобятся, Вам придется копнуть чуть поглубже

Информацию о том, все ли выделенное процессорное время исчерпано, получить нетрудно. Объекты-задания не переходят в свободное состояние до тех пор, пока их процессы нс израсходуют отведенное процессорное время Как только оно заканчи вается, система уничтожает всс процессы в задании и переводит его объект в свобод ное состояние (signaled scate). Это событие легко перехватить с помощью WaitFor SingleObject (или похожей функции). Кстати, потом Вы можете вернуть объект-зада ние в состояние «занято" (nonsignaled state), вызвав SetInformationJobObject и выделив емудополншельное процессорное время.

Когда я только начинал разбираться с заданиями, мне казалось, что объект-зада ние должен переходить в свободное состояние после завершения всех его процес сов. В конце концов, прекращая свою работу, объекты процессов и потоков освобож даются, то же самое вроде бы должно происходить и с заданиями. Нo Microsoft пред почла сделать подругому объект-задание переходит в свободное состояние после того, как исчерпает выделенное ему время Поскольку большинство заданий начина ет свою работу с одним процессом, который существует, пока не завершатся все eго дочерние процессы, Вам нужно просто следить за описателем родительского процес са — он освободится, как только завершится все задание. Моя функция StartRestricted Зrocess как раз и демонстрирует данный прием

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

Создав порт завершения ввода-вывода. Вы сопоставляете с ним задание, вызывая

SetInformationJobObject следующим образом:

JOBOBJECT_ASSOCIATE_COMPLETION_PORT joacp;

joacp.CompletionKey = 1;

// любое значение, уникально идентифицирующее это задание

joacp.CompletionPort = hIOCP;

// описатель порта завершения, принимающего уведомления

SetInformationJobObject(hJob, JobObjectAssociateCompletionPortInforrration, &jоаср, sizeof(joacp))

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

это Вам когда-нибудь понадобится ) Потоки следят за портом завершения ввода-вы вода,

вызывая GetQueuedCompletionStatus.

BOOL GetQueuedCompletionStatus( HANDLE hIOCP, PDWORD pNumBytesTransferred, PULONG_PTR pCorripletionKey, POVERLAPPED *pOverlapped, DWORD dwMilliseconds);

Когда эта функция возвращает уведомление о событии задания, *pCompletionKey содержит значение ключа завершения, заданное при вызове SetInformationJobObjett для связывания задания с портом завершения По нему Вы узнаете, в каком из заданий возникло событие Значение в *pNumBytesTransferred указывет какое именно собы тие произошло (таблица 5-4). В зависимости от конкретного события в *pOverlapped может возвращаться идентификатор процесса.

Событие

Описание

 

 

JOB_OBJECT_MSG_ACTIVE_PROCESS_ZERO

В задании нет работающих процессов

 

 

JOB_OBJECT_MSG_END_OF_PROCESS_TIME

Процессорное время, выделенное процессу, исчерпано, процесс

 

завершается, и сообщается его идентификатор

 

 

JOB_OBJECT_ MSG_ACTIVE_ROCESS_LIMIT

Была попытка превысить ограничение на число активных процессов в

 

задании

 

 

JOB_OBJECT_MSG_PROCESS_MEMORY_LIMIT

Была попытки превысить ограничение на объем памяти, которая

 

может быть передана процессу, сообщается идентификатор процесса

 

 

JOB_OBJECT_MSG_JOB_ MEMORY_LIMIT

Была попытка превысить ограничение на объем памяти, которая

 

может быть передана заданию; сообщается идентификатор процесса

 

 

JOB_OBJECT_MSG_NEW_ PROCESS

В задание добавлен процесс; сообщается идентификатор процесса

 

 

JOB_OBJECT_MSG_EXIT_ PROCESS

Процесс завершен, сообщается идентификатор процесса

 

 

JOB_OBJECT_MSG_ABNOKMAL._EXIT_PROCESS

Процесс завершен из за необработанного им исключения; сообщается

 

идентификатор процесса

 

 

JOB_OBJECT_MSG_END_ OFJOR_TIME

Процессорное время, выделенное заданию, исчерпано, процессы не

 

завершаются, и Вы можете либо возобновить их работу, задав новый

 

лимит по времени, либо самостоя тельно завершить процессы, вызвав

 

TerminateJobObject

Таблица 5-4. Уведомления о событиях задания, посылаемые системой связанному с этим заданием порту завершения

И последнее замечание: по умолчанию объект-задание настраивается системой на автоматическое завершение всех его процессов по истечении выделенного ему про цессорного времени, а уведомление JOB_OBJECT_MSG_END_OF_JOB_TIME не посы лается. Если Вы хотите, чтобы объект-задание не уничтожал свои процессы, а просто сообщал о превышении лимита на процессорное время, Вам придется написать при мерно такой код:

//создаем структуру JOBOBJECT_END_OF_JOB_TIME_JNFORMATION

//и инициализируем ее единственный элемент

JOBOBJECT_END_OF_JOB_TIME_INFORMATION joeojti; joeojti.EndOfJobTimeAction = J0B_OBJECT_POST_AT_END_OF_JOB;

// сообщаем заданию, что ену нужно делать по истечении его времени

SetInformationJobObject(hJob, JobObjectEndOfJobTimeInformation, &joeojti, sizeof(joeojti));

Вы можете указать и другое значение, JOB__OBJECT_TERMINATE_AT_END_OF_JOB,

но оно задается по умолчанию, еще при создании задания

Программа-пример JobLab

Этапрограмма, "05КJobLab.ехе»(см листингнарис 5-6),позволяет легко эксперимен тировать с заданиями Ее файлы исходного кода и ресурсов находятся в каталоге 05-JobLab на компакт-диске, прилагаемом к книге После запуска JobLab открывается окно, показанное на рис 5-5

Рис. 5-5. Программа-пример JobLab

Когда процесс инициализируется, он создает объект «задание» Я присваиваю ему имя JobLab, чтобы Вы могли наблюдать за ним с помощью MMC Performance Monitor Моя программа также создает порт завершения ввода-вывода и связывает с ним объ ектзадание Это позволяет отслеживать уведомления от задания и отображать их в списке в нижней части окна

Изначально в задании нет процессов, и никаких ограничений для него не уста новлено. Поля в верхней части окна позволяют задавать базовые и расширенные ог раничения Все, что от Вас требуется, — ввести в них допустимые значения и щелк нуть кнопкуАрр1у Limits Если Вы оставляете поле пустым, соответствующие ограни чения не вводятся Кроме базовых и расширенных, Вы можете задавать ограничения по пользовательскому