矢量会导致错误共享吗

Can vector cause false sharing

我正在一个项目中使用 C++11,这里有一个函数:

void task1(int* res) {
    *res = 1;
}

void task2(int* res) {
    *res = 2;
}

void func() {
    std::vector<int> res(2, 0); // {0, 0}
    std::thread t1(task1, &res[0]);
    std::thread t2(task2, &res[1]);
    t1.join();
    t2.join();
    return res[0] + res[1];
}

功能就是这样。你看有一个std::vector,它存储了线程的所有结果。

我的问题是:std::vector会导致虚假分享吗?如果可以,在使用std::vector存储线程结果时,有什么方法可以避免错误共享?

can std::vector cause false sharing?

容器不会“导致”虚假共享。它正在写入可能导致错误共享的对象。具体来说,在一个线程中写入与在另一个线程中访问的另一个对象位于同一“缓存行”中的对象会导致错误共享。

数组的元素在内存中相邻,因此数组的相邻小元素很可能位于同一缓存行中。 Vector 是一种基于数组的数据结构。您示例中访问向量元素的模式是错误共享的一个很好的例子。

is there any method to avoid false sharing while using std::vector to store the results of threads?

不要从多个线程写入数组(或向量)的相邻小元素。避免它的方法是:

  • 将数组分成连续的段,并且只从单独的线程访问任何单独的段。分区的大小必须至少是目标系统上缓存行的大小。
  • 或者,写入单独的容器,并在线程完成后合并它们。

是的,如果你在一个std::vector里面写入两个相邻的int元素,很可能它们都在同一个缓存行上,如果这个缓存行会导致虚假共享被两个不同的线程同时访问。

C++17 引入了 std::hardware_destructive_interference_size,这是一种从编译器获取目标平台上 L1 缓存行大小预期的提示的可移植方式。

因此,为防止虚假共享,应确保两个int变量至少相隔std::hardware_destructive_interference_size字节:

void func() {

    constexpr int min_offset = std::hardware_destructive_interference_size / sizeof(int);

    std::vector<int> res( min_offset + 1, 0 );
    std::thread t1( task1, &res[0] );
    std::thread t2( task2, &res[min_offset] );
    t1.join();
    t2.join();
    return res[0] + res[min_offset];
}

然而,在撰写本文时,一些编译器(还)不支持 std::hardware_destructive_interference_size。有关详细信息,请参阅

如果你想合理地确定你的代码在遥远的将来不会有错误共享,那么你可能想假设缓存大小是 std::hardware_destructive_interference_size 报告的大小的两倍。