Защо I/O Completion Port Packets се поставят на опашка във FIFO ред, ако може да бъдат извадени от опашката в различен ред?

Документация на Microsoft за I/O Completion Ports гласи:

Моля, имайте предвид, че докато [completion] пакетите са поставени на опашка във FIFO ред, те могат да бъдат извадени от опашката в различен ред.

Доколкото разбирам, нишката получава пакет за завършване от порт за завършване чрез извикване на GetQueuedCompletionStatus. Защо системата поставя пакети на опашка към порт за завършване във FIFO ред, ако не гарантира, че пакетите ще бъдат извлечени в FIFO ред?


person CRN    schedule 15.01.2015    source източник
comment
Не разбирам какво означава първи влязъл първиизлязъл дори когато първият излязъл не е първият влязъл....   -  person user541686    schedule 15.01.2015
comment
@Mehrdad Добре е да знам, че не съм единственият, който е объркан.   -  person CRN    schedule 15.01.2015
comment
може би това означава, че при прости обстоятелства, използвайки една нишка, пакетите вероятно са FIFO, но различни условия на нишка могат да променят реда. т.е. на опашка във FIFO трябва да е прочел на опашка в реда на вмъкване. но механизмът за премахване на опашката варира по различни причини   -  person slipperyseal    schedule 15.01.2015
comment
FIFO все още означава нещо, дори и да не е строго FIFO. той ви казва, че ще има пропускателна способност на буфера. за разлика от LIFO стека, където може да има пакети, заседнали на дъното.   -  person slipperyseal    schedule 15.01.2015


Отговори (2)


Изявлението, което цитирахте, има за цел да ви накара да знаете, че трябва да направите своя собствена последователност, ако се изисква последователност между I/O завършвания на един сокет. Може да имате нужда от това, ако издавате множество WSARecv извиквания на един сокет. Когато завършат, завършванията ще отидат в IOCP опашката във FIFO ред и това ще бъде редът, в който са били издадени WSARecv извикванията.

Ако продължите да четете този документ, ще видите следното:

Нишките, които блокират изпълнението си на I/O порт за завършване, се освобождават в реда последен влязъл-първи излязъл (LIFO) и следващият пакет за завършване се изтегля от FIFO опашката на I/O порта за завършване за тази нишка. Това означава, че когато пакет за завършване се пусне към нишка, системата освобождава последната (най-скорошната) нишка, свързана с този порт, като му предава информацията за завършване за най-старото I/O завършване.

Което показва, че завършванията се премахват от IOCP във FIFO ред. Причината за първата забележка е, че ако имате множество нишки, чакащи на IOCP, тогава проблемите с планирането на нишките може да означават, че вашият код обработва завършванията в различен ред от реда, в който са били извлечени от IOCP.

Представете си, че имате 2 нишки, обслужващи IOCP и един TCP сокет с 3 чакащи WSARecvs. Достатъчно данни идват от мрежата, за да завършат и трите чакащи WSARecvs и така ще получите три завършвания в IOCP; ще ги наречем A, B & C. Те са в реда, в който са били издадени WSARecv извикванията и така данните в буферите A, B & C трябва да бъдат обработени, за да се поддържа здравината на TCP потока.

На първата от вашите IOCP нишки ще бъде дадено завършване A. На втората нишка ще бъде дадено завършване B. В зависимост от вашия хардуер (брой ядра и т.н.) и програмата за планиране на операционната система или нишка 1, или нишка 2 може да стартират следващата или и двете може бягайте по едно и също време. Това може да ви създаде проблеми в горната ситуация.

Аз лично заобикалям това, като добавям пореден номер към всеки буфер, когато пиша сървъри, които могат да издават множество WSARecv на един сокет. Поредният номер се увеличава, вмъква се в буфера и WSARecv се издава вътре в същата ключалка, така че цялата операция да е атомарна. Когато се появят завършвания, гарантирам, че само една нишка обработва буфери за даден сокет (вижте тук) или използвам „колекция от последователни буфери", която може да гарантира, че буферите се обработват в правилната последователност (вижте тук).

Обърнете внимание също, че за да гарантирате коректността, трябва така или иначе да блокирате издаването на WSARecv (и WSASend) извиквания на даден сокет (вижте тук)

person Len Holgate    schedule 15.01.2015
comment
Благодаря, че сподели прозрението си, Лен. Вашето обяснение и пример ме карат да вярвам, че IOCP всъщност работят по начина, по който очаквах да работи, преди да видя пакетите [completion] на Microsoft да са поставени на опашка във FIFO ред [и] може да бъдат извадени от опашката в различен ред. коментар. Ако разбирам правилно, документацията ще бъде точна, ако се посочва, че пакетите за завършване ВИНАГИ се поставят на опашка и се изваждат от опашка към/от порт за завършване в FIFO ред. Стандартното поведение на нишките (планиране и т.н.) може да повлияе на реда, в който нишките могат да излизат от опашка от порт за завършване - person CRN; 16.01.2015
comment
Това е моето разбиране за това и това е, което моите модулни тестове показват, когато се изпълняват с IOCP, който се обслужва само от една нишка. - person Len Holgate; 16.01.2015

  1. първо направете буфера достатъчно голям, за да приема всички данни, ако е възможно.
  2. НЕ публикувайте получаване от WSARecv няколко пъти за един сокет.
  3. след свързване или след прочитане на данни, обработете тези дати, след което най-накрая публикувайте WSARecv.

сума: само един получаващ буфер за един сокет по всяко време.

Завършвам своя IOCP сървър за страна на сървъра, страна на клиента, четене на файлове, запис, TCP & UDP само за ЕДИН манипулатор на iocp.

person Raymon SHan    schedule 15.01.2015
comment
Правих тест преди години. Задайте размера на получения буфер да удвои размера на прозореца на TCP плъзгача (който е най-много 64k за TCPv4), получете най-добрата производителност. - person Raymon SHan; 16.01.2015