Перекрытый ввод / вывод: как разбудить поток на событии порта завершения или обычном событии? - PullRequest
1 голос
/ 07 июня 2009

Я хочу использовать пул потоков как для запуска, так и для отмены перекрывающихся операций чтения (используя ReadFile() и CancelIo() соответственно), а также для обработки любых событий порта завершения после завершения операций чтения.

  1. Любой поток может инициировать операцию чтения.
  2. Любой поток может обработать событие завершения чтения
  3. Только поток, инициировавший чтение, может отменить его (это ограничение CancelIo())

Я не уверен, как это реализовать. Обычно вызывается GetQueuedCompletionStatus() для ожидания событий завершения порта и WaitForSingleObject() для ожидания обычных событий, но не ясно, как их смешать. Если бы PostQueuedCompletionStatus() позволил бы мне указать конкретную нить для пробуждения, я бы установил. Есть идеи?

ОБНОВЛЕНИЕ : решение должно работать в Windows XP. К сожалению, это исключает использование CancelIoEx() или GetQueuedCompletionStatusEx().

1 Ответ

3 голосов
/ 07 июня 2009

1 и 2 легко, просто используйте порт завершения ввода / вывода.

Но, как вы обнаружили, 3 требует (до Windows V6 1 ) один и тот же поток.

Если используется Windows> = V6, GetQueuedCompletionStatusEx включает изменяемую опцию, которая заставит его вернуться, если в потоке выполняется APC. Поэтому используйте QueueUserAPC, чтобы поставить в очередь неработающий APC 1 , когда вам нужен этот конкретный поток для выполнения какой-либо другой работы. Вам, конечно, понадобится некоторая потокобезопасная очередь, чтобы предоставить прерванному потоку инструкции о том, что отменить.

Если требуется совместимость с более ранними версиями, то все становится сложнее. Возможности:

  • Используйте параметр времени ожидания GetQueuedCompletionStatus] (http://msdn.microsoft.com/library/aa364986), чтобы регулярно возвращаться для проверки отмены.

  • Или, возможно, более практично, разделить пул потоков на две группы. Потоки, которые инициируют и отменяют IO. Все остальное время эти потоки тратят на ожидание сигнала о выполнении одного из этих действий. Другая часть пула ожидает завершения ввода-вывода с GetQueuedCompletionStatus.

Ничто из этого не так приятно, но это всегда проблема старых версий: им не хватает функциональности.

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

...