矢量会导致错误共享吗
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
报告的大小的两倍。
我正在一个项目中使用 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
报告的大小的两倍。