c++ - make_shared<>() 中的 WKWYL 优化是否会为某些多线程应用程序引入惩罚?

标签 c++ caching optimization c++11 shared-ptr

几天前我碰巧看了 Stephan T. Lavavej 的 this very interesting presentation,其中提到了“We Know Where You Live”优化(抱歉在问题标题中使用了首字母缩写词,所以警告我否则问题可能已经关闭),以及 Herb Sutter 在机器架构上的 this beautiful one

简而言之,“We Know Where You Live”优化在于将引用计数器放置在与 make_shared 正在创建的对象相同的内存块上,从而导致一个单一的内存分配而不是两个,并使 shared_ptr 更紧凑。

在总结了我从上面两个演示中学到的东西之后,我开始怀疑如果 shared_ptr 被多个访问者访问,WKWYL 优化是否不能降低性能线程在不同的内核上运行

如果引用计数器接近内存中的实际对象,实际上,它们应该更有可能被提取到与对象本身相同的缓存行中.反过来,如果我得到正确的教训,线程更有可能在竞争同一缓存行时变慢,即使它们不需要。

假设 一个 线程需要多次更新引用计数器(例如在复制 shared_ptr 时),而 其他的只需要访问指向的对象:这会不会通过让所有线程竞争相同的缓存行来减慢它们的执行速度?

如果引用计数存在于内存中的其他位置,我会说发生争用的可能性较小

这是否是反对在类似情况下使用 make_shared() 的一个很好的论据(当然,只要它实现了 WKWYL 优化)?还是我的推理有谬误?

最佳答案

如果那是您的使用模式,那么可以肯定,make_shared 将导致“错误共享”,这是我知道的使用相同缓存行的不同线程的名称,即使他们没有访问相同的字节。

对于附近部分被不同线程(其中一个是写入)使用的任何对象也是如此。在这种情况下,“对象”是由 make_shared 创建的组合 block 。您也可以询问任何试图从数据局部性中受益的尝试是否会适得其反,因为在不同线程或多或少同时使用近端数据的情况下。是的,它可以。

可以得出结论,如果每个对象的每个可写部分都分配在较远的位置,则不太可能发生争用。因此,错误共享的解决方法通常是将内容分散开来(在这种情况下,您可以停止使用 make_shared 或者您可以在对象中添加填充以将其部分分隔到不同的缓存行中)。

与此相反,当在 same 线程中使用不同的部分时,如果您将它们分散到内存中,那么这是有代价的,因为还有更多内容要获取到缓存中。由于分散事物有其自身的成本,因此对于您最初认为的如此多的应用程序而言,这实际上可能无济于事。但毫无疑问,可以编写有帮助的代码。

有时 make_shared 的好处与缓存行和位置无关,它只是进行一次动态分配而不是两次。它的值(value)取决于您分配和释放的对象数量:它可能可以忽略不计;这可能是您的应用程序适合 RAM 与疯狂交换之间的区别;在某些情况下,您的应用可能需要进行所有需要的分配。

仅供引用,还有另一种情况可能不使用 make_shared,那就是对象不小并且您的弱指针明显超过 shared_ptr。原因是控制 block 在弱指针消失之前不会被释放,因此如果您使用 make_shared 则对象占用的整个内存在弱指针消失之前不会被释放。当然,一旦共享指针被销毁,对象就会被销毁,所以重要的是类的大小,而不是关联的资源。

关于c++ - make_shared<>() 中的 WKWYL 优化是否会为某些多线程应用程序引入惩罚?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14342159/

相关文章:

c++ - 来自两个进程的同一文件写入失败

c++ - 如何在 C++ 的 system() 中使用#define?

Java 5 自动过期缓存

javascript - 如何实现 AJAX 响应的缓存?就像在 Internet Explorer 中一样

c++ - 按概率对 if...else if 语句进行排序的效果是什么?

arrays - CUDA中的一维最小卷积

c++ - cvCeil() 比标准库快吗?

c++ - 不同文件中相同命名空间中 2 个不同枚举中的相同标识符

c++ - Windows 和 Linux 中 C++ 中 double 的精度位数不同。为什么? Linux显示超过20个非零精度数字

caching - Ignite Write 内部结构