Пулы потоков
Глава 11 - Пулы потоков
В главе 8 мы обсудили синхронизацию потоков без перехода в режим ядра. Замечательная особенность такой синхронизации — высокое быстродействие. И если Вы озабочены быстродействием потока, сначала подумайте, нельзя ли обойтись синхронизацией в пользовательском режиме.
Вы уже знаете, что создание многопоточных приложений — дело трудное. Вас подстерегают две серьезные проблемы: управление созданием и уничтожением потоков и синхронизация их доступа к ресурсам. Для решения второй проблемы в Windows предусмотрено множество синхронизирующих примитивов: события, семафоры, мьютексы, критические секции и др. Все они довольно просты в использовании. Но если бы сисгема автоматически охраняла разделяемые ресурсы, вот тогда создавать многопоточные приложения было бы по-настоящему легко. Увы, операционной системе Windows до этого еще далеко.
Проблему того, как управлять созданием и уничтожением потоков, каждый решает по-своему. За прошедшие годы я создал несколько реализаций пулов потоков, рассчитанных на определенные сценарии. Однако в Windows 2000 появился ряд новых функций для операций с пулами потоков; эти функции упрощают создание, уничтожение и общий контроль за потоками. Конечно, встроенные в них механизмы носят общий характер и не годятся на все случаи жизни, но зачастую их вполне достаточно, и они позволяют экономить массу времени при разработке многопоточного приложения.
Эти функции дают возможность вызывать другие функции асинхронно, через определенные промежутки времени, при освобождении отдельных объектов ядра или при завершении запросов на асинхронный ввод-вывод.
Пул подразделяется на четыре компонента, которые описываются в таблице 11-1.
|
Компонент поддержки | ||||||||
ожидания |
ввода-вывода |
Других операций таймера | |||||||
Начальное число потоков |
Всегда 1 |
1 |
0 |
0 | |||||
Когда поток создается |
При вызове первой функции таймера пула потоков |
Один поток для каждых 63 зарегист рированных объектов |
В системе применяются эвристические методы, но на создание потока влияют следующие факторы | ||||||
Когда поток разрушается |
При завершении процесса |
При отсутст вии зарегист рированных объектов ожидания |
При отсутствии у потока текущих запросов на ввод-вывод и простое в течение определенного порогового времени (около минуты) |
При простое потока в течение определен ного порогового времени (около минусы) | |||||
Как поток ждет |
В "тревожном"состоянии |
WaitFor Multiple ObjectsEx |
В "тревожном" состоянии |
GetQueued CompletionStatus | |||||
Когда поток пробуждается |
При освобожде нии "ожидаемого таймера", кото рый посылает в очередь АРС-вызов |
При освобождении объекта ядра |
При посылке в очередь АРС-вызова или завершении запроса на ввод- вывод |
При поступлении запроса о статусе завершения или о завершении ввода вывода (порт завер шения требует, чтобы число потоков не превышало число процессоров более чем в 2 раза) |
Таблица 11-1. Компоненты поддержки пула потоков
При инициализации процесса никаких издержек, связанных с перечисленными в таблице компоненчами поддержки, не возникает. Однако, как только вызывается одна из функций пула потоков, для процесса создается набор этих компонентов, и некоторые из них сохраняются до его завершения. Как видите, издержки от применения этих функций отнюдь не малые: частью Вашего процесса становится целый набор потоков и внутренних структур данных. Так что, прежде чем пользоваться ими, тщательно взвесьте все "за" и "против".
О'кэй, теперь, когда я Вас предупредил, посмотрим, как все это работает.