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

时间:2013-12-30 16:16:37

标签: multithreading iocp overlapped-io

使用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进行同步)。 提前感谢您的提示,意见和建议,以便更好地存储(缓存)重叠结构。

1 个答案:

答案 0 :(得分:3)

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

使用单个“池”可以减少“使用用于分配和销毁重叠结构的分配器的所有线程之间的争用”与“发出或处理I / O操作的所有线程之间的争用”之间的争用一件好事。你是正确的,你需要围绕访问进行同步,一个关键部分或者在独占模式下的SRW锁可能是最好的(对于无竞争访问,后者的速度要快一些)。

在长期运行的系统中,堆碎片的减少也是值得的。

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

就我个人而言,我发现我只需要一个单独链接的操作池结构列表(空闲列表)实际上只是一个堆栈,如果我想维护一个“使用中”列表,则需要一个双向链表“每次操作”数据有时是有用的(虽然不是我现在做的事情)。

下一步可能是有几个池,但这取决于系统的设计以及I / O的工作方式。

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