如何确保iocp接收中的线程安全?

How to ensure thread safe in iocp receive?

DWORD bytes;
ULONG_PTR key; ChatOverlappedData* ol;
if (!GetQueuedCompletionStatus(hComp_, &bytes, &key, (LPOVERLAPPED*)&ol, 0)) {
    return false;
}
int type = ol->getNetType();
if (type == net::kAction_Accept) {
    onAccept(ol, bytes, key);
} else if (type == net::kAction_Recv) {
    onRecv(ol, bytes, key);
} else if (type == net::kAction_Send) {

} 
return true; 

考虑以下场景,

客户端alice向服务器发送了两条命令,由三个数据包组成,p1p2p3。前两个包构成第一个命令c1,第三个包构成第二个命令c2。在函数onRecv中,服务器需要将数据包推送到某种命令缓冲区,以形成完整的命令。

但是假设有3个线程t1t2t3,每个线程得到一个数据包(p1,p2,p3) 来自 GetQueuedCompletionStatus,

由于 windows 是抢占式操作系统,线程 t2 可以在 t1t3 之前 运行。结果命令缓冲区将是 p2->p1->p3p2->p3->p1.

数据包推送到命令缓冲区的动作如何保证线程安全?

最简单的解决方案是在每个方向上每个套接字只尝试一个重叠的 I/O 请求。所以 post 一个重叠的读取操作,当它完成时, post 当你处理完第一个时另一个。

发布多个这样的操作非常复杂,因为即使完成将按顺序 posted,处理完成的线程可能会乱序执行,您必须进行一些痛苦和复杂的跟踪.

post在同一连接的同一方向上执行多个重叠操作的好处非常非常小。它几乎永远不足以证明额外的复杂性是合理的。对于处理大量连接的服务器,通常根本不值得这样做,因为额外的内存消耗(或使用较小的缓冲区大小)实际上会使性能变差。

IOCP 的主要好处是更有效地发现哪些连接需要工作,并将该工作有效地分配给线程池。这就是最大 800 个连接的服务器与可以毫不费力地处理 10,000 个连接的服务器之间的区别。