【问题标题】:Modify and read from an atomic variable修改和读取原子变量
【发布时间】:2018-04-11 15:25:40
【问题描述】:

一个类有以下成员,

std::atomic<int> clientId{0};

并在其成员函数中给出以下内容,

int currentId = ++clientId.load();

这里有竞争条件吗?我正在尝试做类似的事情来生成clientId。多个线程可以执行这部分代码。增加了 clientId 的线程是否可以在尝试 load() 并获取副本之前,另一个线程增加相同的值,从而导致竞争条件? 如果是,使用互斥锁进行保护是使用普通 int 并在互斥锁中获取副本的最佳方式吗?

请解释一下。

【问题讨论】:

  • std::atomic&lt;&gt;::load 不返回引用,所以你只是增加一个临时的,这不是竞争条件,但我怀疑这是你想要的......
  • 你可能只是想要int currentId = ++clientId;。
  • 把你的clientId声明放在函数外面。把它放在一个函数中意味着每次都会创建一个新对象,违背了它的目的。回答您的问题,atomic 的工作是防止出现竞争条件等。
  • @Jarod42 clientId 可以在处理到 currentId 之前由另一个线程再次递增吗?

标签: c++ multithreading c++11 c++14 atomic


【解决方案1】:

std::atomic&lt;int&gt;::load() 不返回引用,因此您不会增加clientId 的当前值,而是增加load() 返回的临时值。

你需要做的:

int currentId = ++clientId; // no .load()

overloaded operators 对应于 std::atomic。前置自增运算符的内存顺序为std:: memory_order_seq_cst1,表示:

具有此内存顺序的加载操作执行获取操作,存储执行释放操作,读取-修改-写入执行获取操作和释放操作,加上存在一个所有线程观察所有线程的单一总顺序以相同的顺序进行修改(参见下面的顺序一致的顺序)

因此,您可以避免这里的数据争用情况。

1标准说++clientId等价于fetch_add(1) + 1,fetch_add的默认内存顺序是std::memory_order_seq_cst。

【讨论】:

  • 谢谢。但是在这种情况下,clientId 是否可以在复制到 currentId 之前被另一个线程再次递增?
猜你喜欢
  • 2021-07-06
  • 2015-08-13
  • 1970-01-01
  • 2011-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-12
相关资源
最近更新 更多