简体   繁体   English

std :: thread的线程安全数组?

[英]Thread safe array for std::thread?

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();

The function new_piece writes data to mystruct[i] . 函数new_piece将数据写入mystruct[i] To be more specific, the function changes the values of mystruct[i][0], mystruct[i][1], ..., mystruct[9] 更具体地说,该函数改变了mystruct[i][0], mystruct[i][1], ..., mystruct[9]

How to make the above operation thread safe? 如何使上述操作线程安全?

As mentioned in the comments already, the code seems to be "thread-safe", however it might suffer from "cache-thrashing". 正如评论中已经提到的那样,代码似乎是“线程安全的”,但它可能会受到“缓存抖动”的影响。

First let me explain what it is, and why this might happen in your code: 首先让我解释一下它是什么,以及为什么会在你的代码中发生这种情况:

What is cache-thrashing: 什么是缓存抖动:

A "cache-line" is the smallest unit of data which gets fetched into the cache from memory. “缓存行”是从内存中提取到缓存中的最小数据单元。 Note that the size of the cache-line is a hardware property. 请注意,缓存行的大小是硬件属性。 There's no language construct which would yield this value. 没有语言结构可以产生这个价值。 Most cache-line sizes on modern CPUs are 64 bytes. 现代CPU上的大多数缓存行大小为64字节。

Cache-thrashing occurs on systems with multiple CPUs and a coherent cache when different threads access distinct variables which happen to be layout in memory which share the same cache line. 当不同的线程访问恰好在内存中布局的不同变量(共享相同的高速缓存行)时,在具有多个CPU和一致高速缓存的系统上发生高速缓存抖动。 This will lead to excessive cache misses, and thus results in degraded performance. 这将导致过多的缓存未命中,从而导致性能下降。

(See also wiki article false-sharing ) which refers to the usage pattern which causes cache-thrashing) (另请参阅wiki文章假共享 ),它指的是导致缓存抖动的使用模式

(See also: Dr.Dobb's article Eliminate False Sharing ) (另见:Dr.Dobb的文章消除虚假分享

Why might it happen in your code: 为什么会在您的代码中发生:

Allocation blocks returned from calloc or malloc strive to be as small as possible and are packed tightly together. callocmalloc返回的分配块尽量小,并紧密地打包在一起。 That is, different allocation blocks may share the same cache-line (see also man 3 calloc , eg FreeBSD man page ). 也就是说,不同的分配块可以共享相同的高速缓存行(参见man 3 calloc ,例如FreeBSD手册页 )。

C++'s new operator won't be different. C ++的new运营商不会有所不同。

Now, that we cannot generally assume that memory blocks returned from calloc or malloc will not share a common cache-line, your code may suffer from cache-thrashing, since your instances of mystruct which are accessed simultaneously from different threads may share a common cache-line. 现在,我们通常不能假设从callocmalloc返回的内存块不会共享公共缓存行,您的代码可能会遇到缓存抖动,因为从不同线程同时访问的mystruct实例可能共享一个公共缓存-线。

How to avoid "cache-thrashing": 如何避免“缓存抖动”:

Basically, you ensure this through properly aligning your data (see wiki article Data Structure Alignment ). 基本上,您可以通过正确对齐数据来确保这一点(请参阅Wiki文章数据结构对齐 )。

There are many approaches where you can ensure your data ( mystruct ) is properly cache-aligned, for example: 有许多方法可以确保您的数据( mystruct )正确缓存对齐,例如:

  • Use malloc or calloc and round your allocation requests up to the nearest multiple of the cache-line size. 使用malloccalloc并将分配请求舍入到最接近的缓存行大小的倍数。

  • utilise a posix function: posix_memalign , declared in header <stdlib.h> (see opengroup posix_memalign ) 利用posix函数: posix_memalign ,在头文件<stdlib.h>声明(参见opengroup posix_memalign

  • In C++11, you can use std::aligned_storage (see definition here ) 在C ++ 11中,您可以使用std::aligned_storage (请参阅此处的定义)

    std::aligned_storage provides for a type which is suitable for use as uninitialized storage where you can store your object. std::aligned_storage提供了一个type是适合用作未初始化的存储,可以存储你的对象。

    For example, defining a cache-line aligned storage which is an array for N instances: 例如,定义缓存行对齐的存储,它是N个实例的数组:

     struct mystruct { ... }; const std::size_t cache_line_size = 64; typename std::aligned_storage<sizeof(mystruct), cache_line_size>::type storage[N]; 

    With that, you now could define a class which wraps an array of N cache-line aligned mystruct s, which also provides convenient accessor functions to modify and retrieve a mystruct value at position i in the underlying array. 有了它,您现在可以定义一个包含N个缓存行对齐的mystruct数组的类,它还提供了方便的访问器函数来修改和检索底层数组中位置imystruct值。 IMO, this approach would be much preferred over your error prone approach using a loop and calloc for instantiating the storage for your mystruct array. IMO,这种方法比使用循环和calloc实例化mystruct数组的存储更容易出错。

    See the example here , which - slightly modified - would perfectly fit your needs. 请参阅此处的示例,稍作修改后的示例将完全符合您的需求。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM