Пулы потоков
Пул потоков — это коллекция рабочих потоков, которые эффективно выполняют асинхронные обратные вызовы от имени приложения. Пул потоков в основном используется для уменьшения количества потоков приложения и управления рабочими потоками. Приложения могут помещывать рабочие элементы в очередь, связывать работу с подождаемыми дескрипторами, автоматически выполнять очередь на основе таймера и связываться с ввода-выводами.
Архитектура пула потоков
Следующие приложения могут воспользоваться пулом потоков:
- Приложение, которое является очень параллельным и может отправлять большое количество небольших рабочих элементов асинхронно (например, распределенный поиск индексов или сетевые операции ввода-вывода).
- Приложение, которое создает и уничтожает большое количество потоков, которые выполняются в течение короткого времени. Использование пула потоков может снизить сложность управления потоками и затраты, связанные с созданием и уничтожением потока.
- Приложение, обрабатывающее независимые рабочие элементы в фоновом режиме и параллельно (например, загрузку нескольких вкладок).
- Приложение, которое должно выполнять монопольное ожидание объектов ядра или блокировать входящие события в объекте. Использование пула потоков может снизить сложность управления потоками и повысить производительность, уменьшая количество коммутаторов контекста.
- Приложение, которое создает пользовательские потоки официанта для ожидания событий.
Исходный пул потоков был полностью перемещен в Windows Vista. Новый пул потоков улучшен, так как он предоставляет один рабочий тип потока (поддерживает операции ввода-вывода и не ввода-вывода), не использует поток таймера, предоставляет одну очередь таймера и предоставляет выделенный постоянный поток. Он также предоставляет группы очистки, более высокую производительность, несколько пулов на каждый процесс, запланированный независимо, и новый API пула потоков.
Архитектура пула потоков состоит из следующих элементов:
- Рабочие потоки, выполняющие функции обратного вызова
- Потоки официанта, ожидающие нескольких дескрипторов ожидания
- Рабочая очередь
- Пул потоков по умолчанию для каждого процесса
- Рабочая фабрика, управляющая рабочими потоками
Рекомендации
Новый API пула потоков обеспечивает большую гибкость и управление, чем исходный API пула потоков. Однако есть несколько тонких, но важных различий. В исходном API сброс ожидания был автоматически; в новом API ожидание должно быть явно сброшено каждый раз. Исходный API автоматически обрабатывает олицетворение, передав контекст безопасности вызывающего процесса в поток. С помощью нового API приложение должно явно задать контекст безопасности.
Ниже приведены рекомендации по использованию пула потоков.
Потоки процесса совместно используют пул потоков. Один рабочий поток может выполнять несколько функций обратного вызова одновременно. Эти рабочие потоки управляются пулом потоков. Поэтому не завершайте поток из пула потоков путем вызова TerminateThread в потоке или путем вызова ExitThread из функции обратного вызова.
Запрос ввода-вывода может выполняться в любом потоке в пуле потоков. Отмена ввода-вывода в потоке пула потоков требует синхронизации, так как функция отмены может выполняться в другом потоке, отличном от того, который обрабатывает запрос ввода-вывода, что может привести к отмене неизвестной операции. Чтобы избежать этого, всегда предоставьте структуру OVERLAPPED, с которой был инициирован запрос ввода-вывода при вызове CancelIoEx для асинхронного ввода-вывода или используйте собственную синхронизацию, чтобы убедиться, что другие операции ввода-вывода не могут быть запущены в целевом потоке перед вызовом функции CancelSynchronousIo или CancelIoEx.
Очистите все ресурсы, созданные в функции обратного вызова, перед возвратом из функции. К ним относятся TLS, контексты безопасности, приоритет потока и регистрация COM. Функции обратного вызова также должны восстановить состояние потока перед возвратом.
Сохраняйте дескриптор ожидания и связанные с ними объекты, пока пул потоков не сигнализирует о завершении работы с дескриптором.
Пометьте все потоки, ожидающие длительных операций (например, очистки ввода-вывода или очистки ресурсов), чтобы пул потоков мог выделить новые потоки вместо ожидания этого потока.
Прежде чем выгрузить библиотеку DLL, использующую пул потоков, отмените все рабочие элементы, операции ввода-вывода, операции ожидания и таймеры и дождитесь завершения обратных вызовов.
Избегайте взаимоблокировок путем устранения зависимостей между рабочими элементами и между обратными вызовами, гарантируя, что обратный вызов не ожидает завершения и сохраняет приоритет потока.
Не помещайте слишком много элементов в процесс с другими компонентами с помощью пула потоков по умолчанию. Существует один пул потоков по умолчанию для каждого процесса, включая Svchost.exe. По умолчанию каждый пул потоков имеет не более 500 рабочих потоков. Пул потоков пытается создать больше рабочих потоков, если количество рабочих потоков в состоянии готовности или выполнения должно быть меньше количества процессоров.
Избегайте модели однопоточных квартир COM, так как она несовместима с пулом потоков. STA создает состояние потока, которое может повлиять на следующий рабочий элемент для потока. STA обычно долгое время и имеет сходство потоков, которое является противоположностью пула потоков.
Создайте новый пул потоков для управления приоритетом потока и изоляцией, созданием пользовательских характеристик и, возможно, повышением скорости реагирования. Однако для дополнительных пулов потоков требуется больше системных ресурсов (потоков, памяти ядра). Слишком много пулов увеличивает потенциал для состязания ЦП.
По возможности используйте ожидающий объект вместо механизма на основе APC для сигнала потока пула потоков. Api-интерфейсы не работают так же, как и с потоками пула потоков, так как другие механизмы сигнализации, так как система управляет временем существования потоков пула потоков, поэтому перед доставкой уведомления можно завершить поток.
Используйте расширение отладчика пула потоков , !tp. Эта команда имеет следующее использование:
- Флаги адресов пула
- флаги obj address
- флаги адресов tqueue
- адрес официанта
- рабочий адрес
Для пула, официанта и рабочей роли, если адрес равен нулю, команда дампает все объекты. Для официанта и рабочей роли адрес сбрасывает текущий поток. Определены следующие флаги: 0x1 (однострочные выходные данные), 0x2 (члены дампа) и 0x4 (очередь работы пула дампов).
См. также