Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Пул потоков — это набор рабочих потоков, которые эффективно выполняют асинхронные функции обратного вызова от имени приложения. Пул потоков в основном используется для уменьшения количества потоков приложения и управления рабочими потоками. Приложения могут помещать элементы работы в очередь, связывать работу с ожидаемыми дескрипторами, автоматически ставить её в очередь по таймеру и связывать её с операциями ввода-вывода.
Архитектура пула потоков
Следующие приложения могут воспользоваться пулом потоков:
- Приложение, которое является очень параллельным и может отправлять большое количество небольших рабочих элементов асинхронно (например, распределенный поиск индексов или сетевые операции ввода-вывода).
- Приложение, которое создает и уничтожает большое количество потоков, каждый из которых работает недолго. Использование пула потоков может снизить сложность управления потоками и затраты, связанные с созданием и уничтожением потока.
- Приложение, обрабатывающее независимые рабочие элементы в фоновом режиме и параллельно (например, загрузку нескольких вкладок).
- Приложение, которое должно выполнять монопольное ожидание объектов ядра или блокировать входящие события в объекте. Использование пула потоков может снизить сложность управления потоками и повысить производительность, уменьшая количество коммутаторов контекста.
- Приложение, которое создает пользовательские потоки ожидания для ожидания событий.
Исходный пул потоков был полностью переработан в 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, для передачи сигнала потоку из пула потоков. APC работают с потоками из пула потоков не так эффективно, как другие механизмы сигнализации, поскольку система управляет временем существования потоков из пула, и поэтому поток может быть завершён до доставки уведомления.
Используйте расширение отладчика пула потоков , !tp. Эта команда имеет следующее использование:
- пула адресафлаги
- obj адресфлаги
- tqueue адресафлаги
- адрес официанта
- рабочий адрес
Для pool, waiter и worker, если адрес имеет значение 0, команда выводит все объекты. Для waiter и worker отсутствие адреса приводит к дампу текущего потока. Определены следующие флаги: 0x1 (однострочные выходные данные), 0x2 (члены дампа) и 0x4 (очередь работы пула дампов).
Note
Современные альтернативные варианты: Для приложений C++/WinRT пул потоков Windows доступен через корутины — используется co_await winrt::resume_background() для отправки работы в пул потоков и co_await winrt::resume_foreground(dispatcher) возвращения в поток пользовательского интерфейса. Это обеспечивает структурированное параллелизм без ручного управления обратным вызовом. Для стандартного кода на C++ с политикой std::launch::asyncstd::async обеспечивает переносимый параллелизм на основе задач, хотя при этом пул потоков Windows напрямую не используется.
Связанные разделы