在不同的内存位置同时编写std :: deque是否是线程安全的?

时间:2018-05-31 14:13:33

标签: c++ multithreading c++11 openmp

启动并发块时,我的std::deque<std::pair<CustomObj, int>>大小没有变化。

并发块会读取CustomObj的每个deque并设置int

我可以保证deque不会改变大小因此它不会重新分配,并且每个线程只会访问deque的内存块而不是其他线程的内存块。

是否会导致未定义的行为同时读写?我应该把写作和阅读放在互斥区吗?

3 个答案:

答案 0 :(得分:16)

令我惊讶的是,在目前的标准中,实际上有一个非常明确的部分:

(C ++ 17,26.2.2容器数据竞赛,2)

  
      
  1. 尽管有20.5.5.9,但当同一容器中不同元素中包含的对象的内容同时修改时,需要实现以避免数据争用。
  2.   

此外,您可以毫无顾虑地拨打以下访问者:

  
      
  1. 为避免数据争用(20.5.5.9),实现应考虑以下功能   const:vector<bool>   并且,除了在关联或无序的关联容器中,begin, end, rbegin, rend, front, back, data, find, lower_bound, upper_bound, equal_range, at
  2.   

由于operator[]既不是例外,您可以同时调用这些函数中的任何一个来获取不同的元素并进行修改。只需确保从同时访问和修改元素的并行区域中正确隔离对容器本身的任何修改。

例如,这是错误的:

std::deque

答案 1 :(得分:8)

只要您可以保证deque的大小不会改变,并且只有一个线程会写入特定元素,那么是的,这是安全的。当您尝试修改deque(更改大小)或有多个线程读取和写入deque内的单个元素时,您只会遇到问题。

您可以体验的一件事叫做false sharing。这是具有多个线程使用的元素的单个高速缓存行的过程。由于线程写入会弄脏缓存行,因此整个事情需要重新同步,这将损害性能

答案 2 :(得分:1)

所有标准容器的Arule是:

  • 许多读者整个容器和每个元素上的一个编写者。
  • 单个元素读取或修改(不添加/删除元素)也是对容器的读取操作。

那只是谦虚太强了。你可以做一些违反上述规则的事情而不是标准下的竞争条件。

在标准中,这通常用容器上的const方法表示。读取方法是const,写入方法不是const。唯一的例外是begin()end()以及data()(仅返回迭代器的方法)非const计为const

对于迭代和元素访问,它的措辞是迭代器失效。许多操作使迭代器无效,如果迭代器以其未使用的方式使其无效,则使用它是一种竞争条件。

作为上述经验法则说“不”但标准上写着“确定”的情况的一个例子:

您可以拥有地图和对存储的地图中的值的引用。您可以在另一个线程将键值对添加到地图时编辑该值。

由于没有迭代器被地图无效,而你没有碰到钥匙,我相信没有竞争条件。