【问题标题】:Can this parallel loop cause a data race?这个并行循环会导致数据竞争吗?
【发布时间】:2015-08-25 20:01:26
【问题描述】:

我在并行循环之前用std::pair<Object, bool> 填充了std::vector。布尔值都初始化为true。循环大致如下:

for (int x = 0; x < xMax; ++x) // can parallelising the loop in x cause a data race?
    for (int y = 0; y < yMax; ++y)
        for (auto& i : vector)
            if (i.first.ConstantFunctionDependingOnlyOnInput(x, y))
                i.second = false;

由于我们只是将布尔值设置为false,我认为这不会导致数据竞争,但我不相信我对多线程的直觉。之后对该布尔结果进行的操作在单个线程中完成(使用标准算法擦除向量中bool == true 处的所有元素。

我们将不胜感激。我打算使用std::atomics,但当然,它们不能用于std::vector,因为它们不可复制。

干杯!

【问题讨论】:

  • 我的最终解决方案是使用here 所述的原子包装器,然后将布尔值设为原子。它在单线程中的执行速度非常慢,并且获得了不错的(如果不是完美的)并行加速。结果是一样的,我看不到有数据竞争,因为没有添加或删除任何元素。

标签: c++ multithreading thread-safety data-race


【解决方案1】:

这是一个可能失败的示例,而现实世界的代码正是以这种方式失败的。

    for (auto& i : vector)
        if (i.first.ConstantFunctionDependingOnlyOnInput(x, y))
            i.second = false;

编译器可能会按如下方式优化此代码:

for (auto& i : vector);
{
     bool j = i.second;
     bool k = i.first.Function(x, y);
     i.second = k ? false : j;
}

这可能导致一个线程覆盖另一个线程的结果。这可能是一种合理的优化,因为无条件写入可能比有条件写入便宜,因为它不会被错误预测。

【讨论】:

  • 我怀疑平台/编译器的任何组合都会有任何问题。
  • “内存位置要么是标量类型的对象,要么是所有具有非零宽度的相邻位域的最大序列。” i.first 和 i.second 是不同的内存位置。 i.first 甚至可能包含多个内存位置。
  • 我开始觉得我错过了什么。您究竟想如何并行化循环?那里会有多个线程访问同一个元素吗?如果是,你怎么知道哪个结果很重要?
  • 我认为关于内存位置的第一段是不正确的,但没关系,因为答案的其余部分描述了真正的问题,并且不受它们是否是相同的内存位置的影响。对i.second 的非原子写入告诉编译器没有其他线程将访问它(因为如果他们正在访问它,这将是未定义的行为,所以任何事情都会发生),所以它可以进行大卫展示的转换,并最终将true 写回值。
  • @DavidSchwartz:见stackoverflow.com/q/18303212。那里的答案错了吗?或者你认为 struct 与std::pair&lt;char,char&gt; 有什么根本不同?
【解决方案2】:

您是对的 - 在任何现实世界的系统上,这将完全符合您的预期(没有数据竞争)。虽然官方根据 C++ 标准未定义行为,但现实世界的系统并非以这种方式工作。 Here 是对包括这个问题在内的更广泛问题的回答。

以下是标准中的文本,但说明这是官方未定义的:

如果其中一个修改记忆,则两个表达式计算会发生冲突 location (1.7) 和另一个访问或修改相同的内存 位置。

如果您想要标准保证的安全性,您可以考虑atomic 内存访问。

【讨论】:

  • 您指的是当今存在的现实世界系统。但是你为什么要编写在下一个 CPU、编译器版本或 STL 实现上可能会严重失败的代码呢?
  • 因为它可能更有效。人们经常为了效率而牺牲可移植性——在 OP 的情况下,如果他锁定 bool 访问,他的算法可能会变慢几倍,这取决于他写 bool 的频率。
  • 我已经更新了我的答案以包括原子内存访问的中间选项。
  • 原子在这里是不可能的,它们不能是向量的一部分。
  • @SergeyA 它更复杂但可能:stackoverflow.com/questions/13193484/…
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-09-23
  • 1970-01-01
  • 2021-09-03
  • 2014-02-21
  • 1970-01-01
相关资源
最近更新 更多