Как заставить GetQueuedCompletionStatus() немедленно вернуться?
У меня есть пул ручной работы. Потоки читают из порта завершения и делают другие вещи. Один конкретный поток должен быть закончен. Как прервать его ожидание, если оно зависает на GetQueuedCompletionStatus() или GetQueuedCompletionStatusEx()?
- Конечное время ожидания (100-1000 мс) и выходная переменная далеко не элегантны, вызывают задержки и оставляются в качестве последнего средства.
- CancelIo (завершение порта) в APC в целевом потоке вызывает
ERROR_INVALID_HANDLE
, - CancelSynchronousIo(завершениеПортХандль) вызывает
ERROR_NOT_FOUND
, - PostQueuedCompletionStatus () с завершающим пакетом не позволяет выбрать поток.
- Rough TerminateThread () с мьютексом должен работать. (Я не проверял это.) Но идеологически ли это хорошо?
- Я пытался ждать специального события и завершения порта.
WaitForMultipleObjects()
немедленно вернулся, как будто порт завершения был сигнализирован.GetQueuedCompletionStatus()
шоу ничего не вернуло.
Я прочитал перекрывающийся ввод / вывод: как пробудить поток в событии порта завершения или обычном событии? и много гуглил.
Возможно, сама проблема - завершение работы потока - является признаком плохого дизайна, и все мои потоки должны быть равны и объединены в обычный пул потоков. В этом случае подход PostQueuedCompletionStatus () должен работать. (Хотя у меня есть сомнения, что этот подход красив и лаконичен, особенно если потоки используют GetQueuedCompletionStatusEx () для получения нескольких пакетов одновременно.)
1 ответ
Если вы просто хотите уменьшить размер пула потоков, не имеет значения, какой поток завершается.
Однако, если по какой-то причине вам нужно сообщить конкретному потоку, что он должен выйти, вместо того, чтобы разрешить любому потоку выход, вы можете использовать этот метод.
Если вы используете GetQueuedCompletionStatusEx
Вы можете сделать предупредительное ожидание, передав TRUE
за fAlertable
, Вы можете использовать QueueUserAPC
поставить APC в очередь, которую вы хотите выйти.
Если поток занят, вам все равно придется ждать завершения текущего рабочего элемента.
Конечно, не вызывайте TerminateThread.
К сожалению, дескрипторы портов завершения ввода-вывода всегда находятся в сигнальном состоянии и поэтому не могут использоваться в WaitFor*
функции.
GetQueuedCompletionStatus[Ex]
это единственный способ заблокировать порт завершения. При пустой очереди функция вернется, только если поток получит предупреждение. Как упоминал @Ben,QueueUserAPC
сделает поток предупрежденным и вызовет GetQueuedCompletionStatus
возвращать.
Однако, QueueUserAPC
выделяет память и, следовательно, может дать сбой в условиях нехватки памяти или когда действуют квоты памяти. То же самое и дляPostQueuedCompletionStatus
. Таким образом, использование любой из этих функций на пути выхода не является хорошей идеей.
К сожалению, единственный надежный способ - это вызвать недокументированные NtAlertThread
экспортируется ntdll.dll
.
extern "C" NTSTATUS __stdcall NtAlertThread(HANDLE hThread);
Связать с ntdll.lib
. Эта функция переведет целевой поток в состояние предупреждения, ничего не ставя в очередь.