Пулы потоков

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

Архитектура пула потоков

Использование пула потоков может быть полезным для следующих приложений:

  • Приложение с высокой степенью параллелизма и может асинхронно отправлять большое количество небольших рабочих элементов (например, распределенный поиск по индексу или сетевой ввод-вывод).
  • Приложение, которое создает и уничтожает большое количество потоков, каждый из которых выполняется в течение короткого времени. Использование пула потоков может снизить сложность управления потоками и снизить затраты, связанные с созданием и уничтожением потоков.
  • Приложение, которое обрабатывает независимые рабочие элементы в фоновом режиме и параллельно (например, загружает несколько вкладок).
  • Приложение, которое должно выполнять монопольное ожидание объектов ядра или блокировать входящие события в объекте. Использование пула потоков может снизить сложность управления потоками и повысить производительность за счет уменьшения количества переключений контекста.
  • Приложение, которое создает пользовательские потоки ожидания для ожидания событий.

Исходный пул потоков был полностью перепроектирован в 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
    • адрес официанта
    • рабочий адрес

    Для пула, официанта и рабочей роли, если адрес равен нулю, команда создает дампы всех объектов. Для официанта и рабочей роли пропуск адреса создает дамп текущего потока. Определены следующие флаги: 0x1 (однострочный вывод), 0x2 (члены дампа) и 0x4 (рабочая очередь пула дампов).

API пула потоков

Использование функций пула потоков