线程之间的错误共享是指 2 个或更多线程使用相同的高速缓存行。
例如:
struct Work {
Work( int& d) : data( d ) {}
void operator()() {
++data;
}
int& data;
};
int main() {
int false_sharing[10] = { 0 };
boost::thread_group threads;
for (int i = 0; i < 10; ++i)
threads.create_thread(Work(false_sharing[i]));
threads.join_all();
int no_false_sharing[10 * CACHELINE_SIZE_INTS] = { 0 };
for (int i = 0; i < 10; ++i)
threads.create_thread(Work(no_false_sharing[i * CACHELINE_SIZE_INTS]));
threads.join_all();
}
第一个块中的线程确实遭受错误共享。第二个块中的线程没有(感谢CACHELINE_SIZE
)。
堆栈上的数据总是“远离”其他线程。(例如在windows下,至少有几页)。
使用您定义的函数对象,可能会出现错误共享,因为Work
get 的实例是在堆上创建的,并且该堆空间在线程内部使用。
这可能会导致多个Work
实例相邻,因此可能会导致共享高速缓存行。
但是......您的样本没有意义,因为数据从未在外部接触过,因此不必要地诱导了错误共享。
防止此类问题的最简单方法是将您的“共享”数据本地复制到堆栈上,然后处理堆栈副本。完成工作后,将其复制回输出 var。
例如:
struct Work {
Work( int& d) : data( d ) {}
void operator()()
{
int tmp = data;
for( int i = 0; i < lengthy_op; ++i )
++tmp;
data = tmp;
}
int& data;
};
这可以防止所有共享问题。