Microsoft I/O Completion Ports州的文档:
请注意,虽然[完成]数据包按FIFO顺序排队,但它们可能会以不同的顺序出列。
据我所知,线程通过调用GetQueuedCompletionStatus从完成端口获取完成数据包。如果不保证数据包将以FIFO顺序检索,为什么系统会以FIFO顺序将数据包排队到完成端口?
答案 0 :(得分:3)
您引用的声明旨在让您意识到,如果在单个插槽上的I / O完成之间需要排序,则需要进行自己的排序。如果在单个套接字上发出多个WSARecv调用,则可能需要此选项。完成后,完成将按FIFO顺序进入IOCP队列,这将是WSARecv调用的顺序。
如果你继续阅读该文件,你会看到这篇文章:
阻止在I / O完成端口上执行的线程是 以后进先出(LIFO)订单发布,下一次完成 为此,从I / O完成端口的FIFO队列中提取数据包 线。这意味着,当完成数据包被释放到 线程,系统释放最后一个(最近的)线程关联 使用该端口,将最旧的完成信息传递给它 I / O完成。
这表明以FIFO顺序从IOCP中删除了完成。第一个注意事项的原因是,如果您有多个线程等待IOCP,那么线程调度问题可能意味着您的代码以与从IOCP检索它们的顺序不同的顺序处理完成。
想象一下,你有2个服务于IOCP的线程和一个有3个WSARecvs挂起的TCP套接字。有足够的数据来自网络以完成所有三个待处理的WSARecv,因此您最终会在IOCP中完成三次完成;我们称他们为A,B& C.这些是按照发出WSARecv调用的顺序,因此缓冲区A,B和B中的数据。应该处理C以保持TCP流的健全性。
第一个IOCP线程将被给予完成A.第二个线程将被给予完成B.根据您的硬件(核心数等)和OS调度程序,线程1或线程2可能会运行下一个或两者都可以同时运行。这可能会导致您在上述情况下出现问题。
我个人通过在编写可在单个套接字上发出多个WSARecv的服务器时向每个缓冲区添加序列号来解决此问题。序列号递增,插入缓冲区并在同一锁内发出WSARecv,以便整个操作是原子操作。当完成发生时,我确保只有一个线程处理给定套接字的缓冲区(参见here)或者我使用了一个'顺序缓冲区集合'这可以确保以正确的顺序处理缓冲区(参见here)。
另请注意,为确保正确性,您需要锁定在给定套接字上发出WSARecv(和WSASend)调用(请参阅here)
答案 1 :(得分:2)
总和:任何时候只有一个接收缓冲区用于一个套接字。
我完成了我的IOCP服务器,用于服务器端,客户端,文件读取,写入,TCP& UDP仅适用于一个iocp句柄。