std::future::wait是一个内存屏障吗?(我无法解释这个数据竞争)

5
这里是代码:
std::vector<bool> a(req_count_);
std::vector<std::future<void>> waits(req_count_);

for (int i = 0; i < req_count_; i++) {
  // send into a threadpool implementation
  waits[i] = framework::Async([i, &a] {
    a[i] = true; // write true
  });
}

for (int i = 0; i < req_count_; i++) {
  waits[i].wait(); // memory barrier?
}

int last_req_count = req_count_;
req_count_ = 0;

for (int i = 0; i < last_req_count; i++) {
  if (!a[i]) { // read false
    return false;
  }
}

我的问题是,std::future::wait 是否作为内存屏障?std::future::wait 等待函数调用完成,但是函数 先于 std::future::wait 发生(例如,函数调用引起的状态更改是否在其他线程中可见)?
如果std::future::wait 不作为内存屏障,我们如何实现线程池,以便在未来完成时自动触发内存屏障?
如果您认为我对内存屏障的理解有误,请纠正我。

我一直假定这是一个内存屏障(栅栏),因为否则无法保证一致性。然而,文档并没有明确表述,这可能是文档的不足之处。请参阅关于 std::promise 的文档,其中提到了互斥锁的工作原理:http://en.cppreference.com/w/cpp/thread/promise/set_value - Richard Hodges
感谢 @RichardHodges!我猜这也是一个内存屏障。但是,如果我使用锁来保护变量 a,那么数据竞争就消失了。也许 future::wait 只是确保从 future::get 返回的值是有效的?(试图证明它不是一个内存屏障的可能性) - Helin Wang
来自 C++17 标准:成功设置共享状态存储结果的函数调用与成功检测到该设置引起的就绪状态的函数调用进行同步(4.7)。将结果(无论是正常还是异常)存储到共享状态中与在共享状态上等待函数的成功返回进行同步(4.7)。我怀疑你的问题不在于等待调用本身。 - Caleb
如果您需要在没有锁的情况下在线程之间进行通信,则需要使用<atomic>头文件。 - Mgetz
1个回答

9

[container.requirements.dataraces]/2vector<bool>之外,在同一容器中,不同元素包含的对象的内容并发修改时,实现必须避免数据竞争。

[container.requirements.dataraces]/3 [ 注意: 对于大小大于1的vector<int> x,可以同时执行x[1] = 5*x.begin() = 10而不会发生数据竞争,但是如果同时执行x[0] = 5*x.begin() = 10可能会导致数据竞争。与一般规则不同,对于一个vector<bool> yy[0] = true可能会与y[1] = true有竞争关系。—注 ]

强调是在a[i] = true;处出现的。 vector<bool>并不是一个真正的容器,访问“元素”需要涉及触及相邻元素的位操作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接