Изявлението, което цитирахте, има за цел да ви накара да знаете, че трябва да направите своя собствена последователност, ако се изисква последователност между 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