Luk*_*uka 4 c++ multithreading
mystruct** = (mystruct**)calloc(10, sizeof(mystruct*);
for(unsignd int i = 0; i < 10; i++)
mystruct[i] = (mystruct*)calloc(10, sizeof(mystruct);
thread t[10];
for(unsigned int i = 0; i < 10; i++)
t[i] = thread(new_piece, mystruct[i]);
for(unsigned int i = 0; i < 10; i++)
t[i].join();
Run Code Online (Sandbox Code Playgroud)
该函数new_piece将数据写入mystruct[i].更具体地说,该函数会更改值mystruct[i][0], mystruct[i][1], ..., mystruct[9]
如何使上述操作线程安全?
正如评论中已经提到的那样,代码似乎是"线程安全的",但是它可能会受到"缓存抖动"的影响.
首先让我解释一下它是什么,以及为什么会在你的代码中发生这种情况:
"缓存行"是从内存中提取到缓存中的最小数据单元.请注意,缓存行的大小是硬件属性.没有语言结构可以产生这个价值.现代CPU上的大多数缓存行大小为64字节.
当不同的线程访问恰好在内存中布局的不同变量(共享相同的高速缓存行)时,在具有多个CPU和一致高速缓存的系统上发生高速缓存抖动.这将导致过多的缓存未命中,从而导致性能下降.
(另请参阅wiki文章假共享),它指的是导致缓存抖动的使用模式)
(另见:Dr.Dobb的文章消除虚假分享)
从中返回的分配块calloc或malloc尽可能小的分配块并紧密地组合在一起.也就是说,不同的分配块可以共享相同的高速缓存行(也参见man 3 calloc例如FreeBSD手册页).
C++的new运算符不会有所不同.
现在,我们通常不能假设从共享缓存行返回calloc或malloc不共享内存块,您的代码可能会受到缓存抖动的影响,因为从不同线程同时访问的mystruct实例可能共享一个公共缓存行.
基本上,您可以通过正确对齐数据来确保这一点(请参阅Wiki文章数据结构对齐).
有许多方法可以确保您的数据(mystruct)正确缓存对齐,例如:
使用malloc或calloc舍入分配请求,最多可达缓存行大小的倍数.
利用posix函数:posix_memalign,在标题中声明<stdlib.h>(参见opengroup posix_memalign)
在C++ 11中,您可以使用std::aligned_storage(请参阅此处的定义)
std::aligned_storage提供type适合用作未初始化存储的地方,您可以存储您的对象.
例如,定义缓存行对齐的存储,它是N个实例的数组:
struct mystruct { ... };
const std::size_t cache_line_size = 64;
typename std::aligned_storage<sizeof(mystruct), cache_line_size>::type storage[N];
Run Code Online (Sandbox Code Playgroud)
有了它,您现在可以定义一个包含N个缓存行对齐mystruct的数组的类,它还提供了方便的访问器函数来修改和检索基础数组mystruct中位置i的值.IMO,这种方法比使用循环和calloc实例化mystruct阵列存储的容易出错的方法更受欢迎.
请参阅此处的示例,稍作修改 - 完全符合您的需求.