【问题标题】:False sharing in C++C++ 中的虚假共享
【发布时间】:2012-02-22 07:35:11
【问题描述】:

我有几个遭受缓存争用的类,并使用“new”运算符进行分配。我能否以某种方式确保“新”返回与缓存行对齐的地址?

我正在使用 GCC(如果不能移植的话)。

【问题讨论】:

  • 高速缓存行通常为 64 字节。您必须有一些非常小的类,因此必须执行大量非常小的动态分配?
  • 有些很小,但大多数是重叠的(在缓存行中)。
  • 您是单独分配实例还是在数组中分配实例?
  • 它们是单独分配的。 (不过,我想最关键的部分可以重构为分配在一个数组中。)
  • 我能想到的唯一解决方案是分配sizeof(myobj)+63,然后在64字节边界的地址处使用placement new。

标签: c++ multithreading


【解决方案1】:

您可以将memalign 或_aligned_alloc 分别用于glibc 或windows CRT 系统。你甚至可以使用像 nedmalloc 这样的自定义分配器并让它对齐块,这也可以给你一些其他额外的好处。

您还应该用__attribute__((aligned(64))) 标记它们,以防它们被静态分配。

【讨论】:

    【解决方案2】:

    解决这个问题的最简单方法是使对象足够大,以至于它们不能共享缓存行。使用 gcc 您可以设置类的对齐方式(我假设您的对象比缓存线小,因为您遭受争用):

    class foo {} __attribute__((aligned(2 * CL)));
    

    当然,您需要为 CL 的架构插入正确的 Cachelinesize(或将其放入宏中并在那里使用)。我使用了两倍大小的缓存行,因为据我记得new 并不能保证它实际上会确保保持对齐。由于不能保证对象从缓存行的开头开始,您仍然可以在同一缓存行中获取不同对象的部分(即一个对象的结尾,另一个对象的开头)。如果始终保持对齐,__attribute__((aligned(CL))) 就可以了。当然,这需要你改变结构并浪费大量空间。

    您也可以基于memalign 编写自己的new(查看here 了解如何操作)。对于更方便的解决方案,您还可以直接使用memalign 并使用placement new 将对象放在分配的空间内。当然,这会使使用这些对象的代码变得不那么好。

    【讨论】:

      【解决方案3】:

      您可以使用placement new 将对象构造到给定的内存区域中:

        // Instantiate object into a pre-allocated buffer
        obj = new (buf) TheClass();
      

      要获得对齐的缓冲区buf,您可以使用memalign、sbrk 或mmap。

      【讨论】:

      • 我看不到问题和mmap之间的关系。为什么mmap?
      猜你喜欢
      • 2019-03-07
      • 2012-01-10
      • 2012-06-17
      • 1970-01-01
      • 1970-01-01
      • 2014-03-14
      • 2015-07-01
      • 2016-09-27
      • 1970-01-01
      相关资源
      最近更新 更多