良好的交叉线程分配和免费分配器

时间:2013-10-02 22:38:28

标签: c++ multithreading memory-management

我打算编写一个C ++联网应用程序,其中:

  1. 我使用单个线程接受TCP连接,并从中读取数据。我打算用epoll / select来做这件事。数据被写入使用某些竞技场分配器分配的缓冲区中,例如jemalloc。
  2. 一旦有足够的数据来自单个TCP客户端以形成协议消息,数据就会发布在环形缓冲区中。环形缓冲区结构包含连接的fd和指向包含相关数据的缓冲区的指针。
  3. 工作线程处理来自环形缓冲区的条目,并将一些结果数据发送到客户端。处理完每个事件后,工作线程释放实际的数据缓冲区,将其返回到竞技场分配器以供重用。
  4. 我遗漏了有关发布者如何将其编写的数据显示给工作线程的详细信息。

    所以我的问题是:是否有任何分配器可以优化这种行为,即在一个线程上分配对象并在另一个线程上释放?

    我特别担心必须使用锁来将内存返回到一个不是线程关联竞技场的竞技场。我也担心错误共享,因为生产者线程和工作线程都将写入同一区域。看起来像jemalloc或tcmalloc都没有针对此进行优化。

2 个答案:

答案 0 :(得分:3)

在为多线程应用程序实现高度优化的分配器之前,首先应该使用标准newdelete运算符来实现。在正确实现应用程序之后,您可以解决通过分析它发现的瓶颈问题。

如果您进入显然标准newdelete分配器是应用程序瓶颈的阶段,以下是我使用的方法:

假设:线程数是固定的,并且是静态创建的。

  • 每个帖子都有自己的竞技场。
  • 从竞技场中取出的每个物体都有一个参考它回来的竞技场。
  • 每个竞技场都有一个单独的垃圾清单。
  • 当一个线程释放一个对象时,它会返回它来自的竞技场,但是被置于特定于线程的垃圾列表中。
  • 实际拥有竞技场的线程将其垃圾清单视为真正的免费列表。
  • 定期拥有竞技场的线程执行垃圾收集传递,将对象从其他线程垃圾列表中折叠到真正的空闲列表中。

“定期”垃圾收集通行证不一定必须基于时间。例如,垃圾的一部分可以在每次分配时获得并且是免费的。

答案 1 :(得分:3)

处理内存分配和释放问题的最佳方法是不处理它。

你提到了一个环形缓冲区。这些通常是固定的大小。如果您可以为协议消息提供固定的最大大小,则可以分配程序启动时所需的所有内存。取消分配时,请保留内存,但将其重置为新状态。

现在,您的程序可能需要在处理每条消息时分配和释放内存,但这将在每个线程中完成,并且跨线程问题将无法发挥作用。

即使您的消息最大大小太大而无法预分配,如果您可以分配大多数消息将使用的内存量并且在必要时分配更多处理程序,这也可以正常工作。