Утверждение, которое вы цитируете, предназначено для того, чтобы вы знали, что вам нужно выполнять собственную последовательность, если последовательность требуется между завершениями ввода-вывода в одном сокете. Это может понадобиться, если вы выполняете несколько вызовов WSARecv на одном сокете. Когда они завершатся, завершения перейдут в очередь IOCP в порядке FIFO, и это будет порядок, в котором были отправлены вызовы WSARecv.
Если вы продолжите читать этот документ, вы увидите этот фрагмент:
Потоки, которые блокируют свое выполнение на порте завершения ввода-вывода, высвобождаются в порядке «последним поступил — первым обслужен» (LIFO), и следующий пакет завершения извлекается из очереди FIFO порта завершения ввода-вывода для этого потока. Это означает, что когда пакет завершения передается потоку, система освобождает последний (самый последний) поток, связанный с этим портом, передавая ему информацию о завершении для самого старого завершения ввода-вывода.
Что показывает, что завершения удаляются из IOCP в порядке FIFO. Причина первого примечания заключается в том, что если у вас есть несколько потоков, ожидающих IOCP, то проблемы с планированием потоков могут означать, что ваш код обрабатывает завершения в порядке, отличном от порядка, в котором они были получены из IOCP.
Представьте, что у вас есть 2 потока, обслуживающих IOCP, и один сокет TCP с 3 ожидающими обработки WSARecv. Из сети поступает достаточно данных для завершения всех трех ожидающих выполнения WSARecv, и поэтому в IOCP вы получаете три завершения; мы назовем их A, B и C. Они расположены в том порядке, в котором были отправлены вызовы WSARecv, поэтому данные в буферах A, B и C должны обрабатываться для поддержания работоспособности потока TCP.
Первому из ваших потоков IOCP будет дано завершение A. Второму потоку будет дано завершение B. В зависимости от вашего оборудования (количество ядер и т. д.) и планировщика ОС либо поток 1, либо поток 2 могут быть запущены следующим, либо оба могут бежать одновременно. Это может вызвать у вас проблемы в описанной выше ситуации.
Я лично обхожу это, добавляя порядковый номер к каждому буферу при написании серверов, которые могут выдавать несколько WSARecv на одном сокете. Порядковый номер увеличивается, вставляется в буфер, а WSARecv выдается внутри той же блокировки, так что вся операция является атомарной. Когда происходит завершение, я гарантирую, что только один поток обрабатывает буферы для данного сокета (см. ">здесь), или я использую "упорядоченную коллекцию буферов", которая может гарантировать, что буферы обрабатываются в правильной последовательности (см. здесь).
Также обратите внимание, что для обеспечения корректности вам в любом случае необходимо заблокировать вызовы WSARecv (и WSASend) для данного сокета (см. html" rel="nofollow">здесь)
person
Len Holgate
schedule
15.01.2015