Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых
<

Программирование для Windows NT

© Александр Фролов, Григорий Фролов
Том 26, часть 1, М.: Диалог-МИФИ, 1996, 272 стр.
Рецензия PC WEEK

[Назад] [Содеожание] [Дальше]

Управление запущенными задачами

После того как задача запущена, запустившая задача знает идентификатор дочерней задачи. Этот идентификатор возвращается функциями CreateThread XE "CreateThread" , _beginthread XE "_beginthread" и _beginthreadex XE "_beginthreadex" . Пользуясь этим идентификатором, запустившая задача может управлять состоянием дочерней задачи, изменяя ее приоритет, приостанавливая, возобновляя или завершая ее работу.

Изменение приоритета задачи

В разделе “Относительный приоритет задач” нашей книги мы рассказали вам о том, как в операционной системе Microsoft Windows NT устанавливаются приоритеты задач. Родительская задача может изменить относительный приоритет запущенной ей дочерней задачи с помощью функции SetThreadPriority XE "SetThreadPriority" :


BOOL SetThreadPriority(
  HANDLE hThread,    // идентификатор задачи 
  int    nPriority); // новый уровень приоритета задачи

Через параметр hThread этой функции передается идентификатор задачи, для которой необходимо изменить относительный приоритет.

Новое значение относительного приоритета передается через параметр nPriority и может принимать одно из следующих значений:

·       THREAD_PRIORITY_TIME_CRITICAL;

·       THREAD_PRIORITY_HIGHEST;

·       THREAD_PRIORITY_ABOVE_NORMAL;

·       THREAD_PRIORITY_NORMAL;

·       THREAD_PRIORITY_BELOW_NORMAL;

·       THREAD_PRIORITY_LOWEST;

·       THREAD_PRIORITY_IDLE

Абсолютный уровень приоритета, который получит задача, зависит от класса приоритета процесса. Забегая вперед, скажем, что класс приоритета процесса можно изменить при помощи функции SetPriorityClass XE "SetPriorityClass" .

Определение приоритета задачи

Зная идентификатор задачи, нетрудно определить ее относительный приоритет. Для этого следует воспользоваться функцией GetThreadPriority XE "GetThreadPriority" :


int GetThreadPriority(HANDLE hThread);

Эта функция возвращает одно из значений, перечисленных выше в разделе “Изменение приоритета задачи” или значение THREAD_PRIORITY_ERROR_RETURN XE "THREAD_PRIORITY_ERROR_RETURN" при возникновении ошибки.

Приостановка и возобновление выполнения задачи

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

Приостановка выполнения задачи выполняется с помощью функции SuspendThread XE "SuspendThread" :


DWORD SuspendThread(HANDLE hThread);

Через единственный параметр этой функции нужно передать идентификатор приостанавливаемой задачи.

Для каждой задачи операционная система хранит счетчик приостановок, который увеличивается при каждом вызове фукнции SuspendThread XE "SuspendThread" . Если значение этого счетчика больше нуля, задача приостанавливается.

Для уменьшения значения счетчика приостановок и, соответственно, для возобновления выполнения задачи вы должны использовать фукнцию ResumeThread XE "ResumeThread" :


DWORD ResumeThread(HANDLE hThread);

В случае ошибки функции SuspendThread и ResumeThread возвращают значение 0xFFFFFFFF.

Временная приостановка работы задачи

С помощью функции Sleep задача может приостановить свою работу на заданный период времени:


VOID Sleep(DWORD cMilliseconds); // время в миллисекундах

Задача, выполняющая ожидание с помощью этой функции, не снижает производительность системы, так как ей не распределяются кванты времени. Через единственный параметр вы можете задать функции время ожидания в миллисекундах.

Если для времени ожидания указать нулевой значение, то при наличии в системе запущенных задач с таким же приоритетом, как и у задачи, вызвавшей эту функцию, ожидающая задача отдает оставшееся время от своего кванта другой задаче. В том случае, когда в системе нет других задач с таким же значением приоритета, функция Sleep XE "Sleep" немедленно возвращает управление вызвавшей ее задаче, которая сама будет использовать остаток своего кванта времени.

Есть еще одна возможность: можно организовать бесконечную задержку, передав функции Sleep XE "Sleep" значение INFINITE XE "INFINITE" .

Завершение задачи

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

Для того чтобы завершить свое выполнение, задача, запущенная с помощью фукнции CreateThread XE "CreateThread" , может вызвать функцию ExitThread XE "ExitThread" , передав ей код завершения:


VOID ExitThread(DWORD dwExitCode);

Для принудительного завершения дочерней задачи родительская задача может использовать функцию TerminateThread XE "TerminateThread" , передав ей идентификатор завершаемой задачи и код завершения:


BOOL TerminateThread(
  HANDLE hThread,     // идентификатор завершаемой задачи 
  DWORD  dwExitCode); // код завершения 

Как родительская задача может получить код завершения дочерней задачи?

Для этого она должна вызвать фукнцию GetExitCodeThread:


BOOL GetExitCodeThread(
  HANDLE  hThread,     // идентификатор завершаемой задачи 
  LPDWORD lpExitCode); // адрес для приема кода завершения

Если задача, для которой вызвана фукнция GetExitCodeThread, все еще работает, вместо кода завершения возвращается значение STILL_ACTIVE.

Как мы уже говорили, если задача была запущена с помощью функций _beginthread или _beginthreadex, она может завершать свое выполнение только с помощью функций, соответственно, _endthread и _endthreadex. Функцию ExitThread XE "ExitThread" в этом случае использовать нельзя, так как при этом не будут освобождены ресурсы, заказанные для работы с мультизадачным вариантом библиотеки времени выполнения.

Освобождение идентификатора задачи

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

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

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

[Назад] [Содеожание] [Дальше]