使用std :: atomic <t> </t>的条件的基本用法

时间:2014-10-30 15:17:05

标签: c++ c++11 atomic

所以我开始熟悉C ++ 11 <atomic>类型。在过去,当我有一个原子标志时,我通常只是在访问它之前锁定一个互斥锁。一个常见的需求是检查标志是否为false,如果是,则自动将其设置为true然后执行某些操作。所以基本上这样就可以实现,其中flag是一个简单的bool

{
    std::lock_guard<std::mutex> lock(my_mutex);
    if (!flag) 
    {
        flag = true;
        // do something;
    }
}

所以,现在我想弄清楚如何用<atomic>完成同样的事情。 docs表示赋值运算符和原子类型的operator T是原子操作。但是,如果我将flag更改为std::atomic<bool>,我想我不能简单地说:

if (!flag)
{
  flag = true;
  // do something
}

...因为即使表达式(!flag)是原子的,并且赋值flag = true是原子的,也没有什么可以防止另一个线程在这两个语句之间修改标志。< / p>

所以,如果我在这里正确理解,唯一正确的用法 - 在所有 - 具有原子类型的条件,其中条件的结果可以修改原子变量,是使用比较和交换操作?我是对的吗?

所以,我不得不说:

bool expected = false;
if (flag.compare_exchange_weak(expected, true))
{
   // do something
}

我的理解是否正确?

3 个答案:

答案 0 :(得分:5)

如果您有多个运行相同代码的线程需要进行翻转,是的 - 您需要使用compare_exchange_weak()compare_exchange_strong(),因为您建议的原因(可能更喜欢强大) )。

然而,并非如此说这是使用原子的唯一正确使用条件的情况。如果我有一个只读取原子的线程和写入它的线程,那么以简单的方式使用它们是完全合理的......例如:

std::atomic<bool> done{false};

// thread 1
while (!done) {
    ....
}

// thread 2
stop() { done = true; }

我没有理由在那里做done.compare_exchange_strong(expected, true)。这太过分了。它确实是在个案的基础上。

答案 1 :(得分:1)

话虽如此,你可能更喜欢compare_exchange_strong,除非你处于紧张状态。它可能导致性能降低,但可以保证为您提供您期望的结果(compare_exchange_weak不是)。

答案 2 :(得分:0)

明显的注意:锁定语义与原子检查完全不同,因为在这种情况下,另一个线程等待锁定释放,并且在获取锁定后将始终执行其操作。因此,严格来说,两个代码示例并不相同。