多线程IOCP服务器中重叠结构的存储与管理

Posted

技术标签:

【中文标题】多线程IOCP服务器中重叠结构的存储与管理【英文标题】:storage and management of overlapped structure in multithreaded IOCP server 【发布时间】:2013-12-30 16:16:36 【问题描述】:

使用 LINKED LIST 存储重叠结构是个好主意吗?

我的重叠结构是这样的

typedef struct _PER_IO_CONTEXT 


  WSAOVERLAPPED               Overlapped;
  WSABUF                      wsabuf;
  ....
  some other per operation data
  ....
  struct _PER_IO_CONTEXT      *pOverlappedForward;
  struct _PER_IO_CONTEXT      *pOverlappedBack;

  PER_IO_CONTEXT, *PPER_IO_CONTEXT;

当 iocp 服务器启动时,我在链接列表中分配(例如)其中的 5000 个。此列表的开头存储在全局变量 PPER_IO_CONTEXT OvlList 中。我必须补充一点,我只在必须向所有连接的客户端发送数据的情况下使用这个链表。 当 Wsasend 发布或 GQCS 收到通知时,更新链表(我使用 EnterCriticalSection 进行同步)。 提前感谢您对更好的存储(缓存)重叠结构的提示、意见和建议。

【问题讨论】:

为什么不使用内置的数据结构,如向量或包/集?您是否仅限于 C 语言? @usr 我不限于 C,但我的编程技能仍然很小,我需要一些更好的程序员的建议。 Vector?,我可以在多线程服务器中使用它吗?同步呢? 您还必须同步对自定义链表的访问。那里没有区别。通过自己构建所有东西,你会让你的工作变得更难,而不是更容易。尝试从更高的层次思考,而不是构建自己的数据结构。 我只是将这些东西推到一个传统的线程安全的生产者-消费者队列中,作为一个池。 如果我正在构建一个,我可能会使用双端队列 - 只需要访问末端,(带有临界区和信号量)。 【参考方案1】:

我假设建议的用例是您希望缓存“每个操作”重叠结构以避免重复分配和释放动态内存,这可能导致分配器争用和堆碎片。

使用单个“池”将争用从“使用用于分配和销毁重叠结构的分配器的所有线程之间的争用”减少到“所有发出或处理 I/O 操作的线程之间的争用”,这通常是一件好事。您是对的,您需要围绕访问进行同步,关键部分或独占模式下的 SRW 锁可能是最好的(后者对于非竞争访问来说要快一点)。

堆碎片的减少也值得在长时间运行的系统中实现。

使用“标准”非侵入性列表,例如std::deque,起初看起来是显而易见的选择,但非侵入性集合的问题在于它们倾向于为每个操作分配和释放内存(所以你回来了你原来的论点)。恕我直言,最好在每个重叠的结构中放置一个指针并将它们简单地链接在一起。这不需要在访问池时分配或释放额外的内存,这意味着您的争用会回到使用池的线程。

我个人发现我只需要一个池(空闲列表)的每个操作结构的单链表,它实际上只是一个堆栈,如果我想维护一个“使用中”的列表,我需要一个双链表'per-operation' 数据有时很有用(虽然不是我现在做的事情)。

下一步可能是创建多个池,但这取决于您的系统设计和 I/O 的工作方式。

如果您可以对给定连接进行多个挂起的发送和接收操作,那么在连接级别设置一个小型池可能会很有用。这可以显着减少单个共享池的争用,因为每个连接都会首先尝试使用每个连接池,如果该池为空(或已满)则回退到使用全局池。这往往会导致对全局池锁的争用要少得多。

【讨论】:

,非常有用的答案。如果有人想知道 iocp 的工作原理,阅读本网站上关于 iocp 的大部分答案也很有帮助。非常感谢。

以上是关于多线程IOCP服务器中重叠结构的存储与管理的主要内容,如果未能解决你的问题,请参考以下文章

向多线程 iocp 服务器中的新连接用户发送连接用户列表

Windows完成端口 IOCP模型

多线程 IOCP 客户端问题

如何使用 IOCP 将用户定义的数据传递给工作线程?

IOCP实现高并发以及与传统socke编程的对比

IOCP 线程 - 澄清?