Дополнительные функции управления потоками

Несмотря на то что функций управления потоками, которые мы выше обсуждали, вполне достаточно для большинства случаев, в том числе и для примеров, приведенных в этой книге, в Windows XP и Windows Server 2003 были введены две дополнительные функции. Их краткие описания представлены ниже.

1. Функция GetProcessIdOfThread, требующая использования Windows Server 2003, позволяет получать идентификатор процесса, которому принадлежит поток, по известному дескриптору потока. Вы могли бы задействовать эту функцию в программах, предназначенных для управления потоками, принадлежащими другим процессам, или взаимодействия с такими потоками. Если необходимо получить дескриптор процесса, применяйте для этого функцию OpenProcess.

2. Функция GetThreadIOPendingFlag позволяет определить, имеются ли у потока, на который указывает дескриптор, необслуженные запросы ввода/вывода. Например, поток мог быть заблокирован во время выполнения операции ReadFile. В качестве результата возвращается состояние потока во время выполнения данной функции; фактическое состояние может в любой момент измениться, если целевой поток завершает или начинает выполнение операции. Эта функция требует использования NT 5.1 и поэтому доступна лишь в Windows XP или Windows Server 2003.

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

Для каждого потока поддерживается счетчик приостановок (suspend count), и выполнение потока может быть продолжено лишь в том случае, если значение этого счетчика равно 0. Поток может увеличивать или уменьшать значение счетчика приостановок другого потока с помощью функций SuspendThread и Resume-Thread. Вспомните, что поток можно создать в приостановленном состоянии со счетчиком приостановок равным 1.

DWORD ResumeThread(HANDLE hThread)

DWORD SuspendThread(HANDLE hThread)

В случае успешного выполнения обе функции возвращают предыдущее значение счетчика приостановок, иначе — 0xFFFFFFFF.

Ожидание завершения потока

Поток может дожидаться завершения выполнения другого потока точно так же, как потоки могут дожидаться завершения процесса, что обсуждалось в главе 6. В этом случае при вызове функций ожидания (WaitForSingleObject и WaitForMultipleObjects) вместо дескрипторов процессов следует использовать дескрипторы потоков. Заметьте, что не все дескрипторы в массиве, передаваемом функции WaitForMultipleObjects, должны быть обязательно одного и того же типа; например, в одном вызове могут быть одновременно указаны дескрипторы потоков, процессов и других объектов.

Допустимое количество объектов, одновременно ожидаемых функцией WaitForMultipleObjects, ограничено значением MAXIMUM_WAIT_OBJECTS (64), но при большом количестве потоков можно воспользоваться серией вызовов функций ожидания. Эта техника уже была продемонстрирована в программе 6.1; программы, приведенные в книге, ожидают завершения выполнения одиночных объектов, но на Web-сайте приведены полные решения.

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

Заметьте, что дожидаться перехода в сигнальное состояние одного и того же объекта могут одновременно несколько потоков. Аналогично, функция ExitProcess переводит в сигнальное состояние как сам процесс, так и все его потоки.

Удаленные потоки

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

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

Понятие о потоках твердо упрочилось во многих ОС, и исторически так сложилось, что многие поставщики и пользователи UNIX предоставляли собственные частные варианты их реализации. Были разработаны некоторые библиотеки, обеспечивающие многопоточную поддержку вне ядра. В настоящее время стандартом в этой области являются потоки POSIX Pthreads. Потоки Pthreads включены в частные варианты реализации UNIX и Linux и иногда считаются частью UNIX. Соответствующие системные вызовы отличаются от обычных системных вызовов UNIX наличием в именах префикса pthread. Потоки Pthreads поддерживаются также некоторыми другими системами, отличными от UNIX, такими, например, как Open VMS.

Системный вызов pthread_create эквивалентен вызову CreateThread, a системный вызов pthread_exit — вызову ExitThread. Для организации ожидания одним потоком завершения другого применяется системный вызов pthread_join. Потоки Pthreads предоставляют очень полезную функцию pthread_cancel, гарантирующую, в отличие от функции TerminateThread, выполнение обработчиков завершения и уничтожение ненужных дескрипторов. Возможность уничтожения потоков была бы в Windows крайне желательной, но в главе 10 представлен метод, обеспечивающий получение такого же эффекта.

Четыре функции управления


Похожие статьи.

Понравилась статья? Поделиться с друзьями: