首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在不同的内存位置并发编写std::deque是线程安全的吗?

问在不同的内存位置并发编写std::deque是线程安全的吗?
EN

Stack Overflow用户
提问于 2018-05-31 22:13:33
回答 3查看 734关注 0票数 13

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

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

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

这是否会导致同时读取和写入的未定义行为?我应该把写和读放在一个互不相容的区域吗?

EN

回答 3

Stack Overflow用户

发布于 2018-06-01 00:52:33

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

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

  1. Notwithstanding 20.5.5.9,当同时修改同一容器中不同元素中包含的对象的内容( vector<bool>除外)时,需要实现以避免数据争用。

同样,你也可以不用担心调用下面的访问器:

为了避免数据争用(20.5.5.9),实现应将以下函数视为常量:operator[].和

  1. ,除非在关联或无序关联容器中

由于std::deque也不例外,因此您可以并发调用这些函数中的任何一个来获取不同的元素并对其进行修改。只需确保将对容器本身的任何修改与并发访问和修改元素的并行区域隔离开即可。

例如,这将是错误的:

代码语言:javascript
复制
std::dequeue<...> dq;
#pragma omp master
{
    ...
    dq.emplace(...);
}
// no implicit barrier here,
// use omp barrier or change to omp single instead of master
#pragma omp for
for (... i; ...)
    dq[i].second = compute(dq[i]);
票数 16
EN

Stack Overflow用户

发布于 2018-05-31 22:18:36

只要你能保证deque的大小不会改变,并且只有一个线程会写入特定的元素,那么是的,这是安全的。只有当您试图修改deque (更改其大小)时,或者当您有多个线程对deque中的单个元素进行读写时,才会出现问题。

不过,你可能会体验到一种叫做false sharing的东西。这是具有正由多个线程使用的元素的单个高速缓存线的过程。由于线程写操作会弄脏缓存行,因此整个过程需要重新同步,这会损害性能

票数 7
EN

Stack Overflow用户

发布于 2018-05-31 23:20:26

所有标准容器的规则是:

在整个容器和每个element.

  • Individual元素上读取或修改(不添加/删除元素)的多个读取器或一个写入器也是容器上的
  • 操作。

这只是略微太强了。您可以做少量违反上述规则的事情,而不会成为标准下的竞争条件。

在标准中,这通常是根据容器上的const方法来表达的。读取方法为const,写入方法不为const。例外情况是非const的begin()、end()和data() (只返回迭代器的方法)被视为const。

对于迭代和元素访问,它是根据迭代器无效来表述的。很多操作都会使迭代器失效,如果迭代器在使用时以无序的方式失效,这就是竞争条件。

举一个例子,上面的经验法则说“不”,但标准说“好”:

您可以存储映射和对映射中某个值的引用。您可以在另一个线程向映射中添加键值对时编辑值。

由于没有迭代器被映射无效,并且您没有接触到键,所以我认为没有竞争条件。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50626405

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档