【问题标题】:std::atomic<int> decrement and comparisonstd::atomic<int> 递减和比较
【发布时间】:2011-12-15 23:36:39
【问题描述】:

关于以下代码:

std::atomic<int> myint; //Shared variable
//(...)
if( --myint == 0) {
    //Code block B
}

是否可能有多个线程访问我命名为“代码块 B”的块?

请考虑不会发生溢出,'if' 被多个线程同时执行,整个程序中对 myint 的唯一修改是 -- myint 在 if 和那个 myint 被初始化为一个正值。

【问题讨论】:

  • @Patrick 那将是未定义的行为。
  • 真正的问题是 std::atomic::operator-- 是否以原子方式返回旧值。
  • @cdleonard - 递减是原子的并返回结果。但是,当您将结果与零进行比较时,没有什么可以阻止另一个线程立即增加或减少值。
  • @BoPersson 但是返回的值不会被任何后续对 myint 的修改所修改。所以,理论上,如果 myint 的值单调递减(折扣溢出),那么只有单个线程可以进入块。
  • @curiousguy 我不知道你在说什么,我从来没有在我的问题上说“下溢”... =)

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


【解决方案1】:

不,考虑到您的限制,不可能有多个线程进入块。但也不能保证任何线程都会进入这个块:

thread A: decrement myint to 0

thread B: decrement myint to -1

thread A: compare to 0 -> false -> don't enter (and neither anyone else)

如果这是一个问题(我假设),那么这段代码将不起作用(至少不是总是)。

【讨论】:

  • 如果我有:线程 A:减 1,线程 B:减 0,线程 A:比较 0 真,线程 B:比较 0 真。
  • @AndréPuel 啊,我想你明白了(和你的答案)。
  • @AndréPuel 这是不可能的,-- 运算符在一条指令中执行递减和获取,因此即使按照您在评论中指定的执行顺序,线程 A 中的值也是 1。跨度>
  • @SoapBox 这正是我要问的! operator-- 标准是否定义了递减和取值必须以原子方式完成?
【解决方案2】:

代码块总是执行并不明显。如果操作符“--”的实现方式是将旧值存储在其返回值中,并在单个原子指令中递减(我很确定 x86 有这样的指令),那么是的,它应该像一个多个线程的互斥块。我不确定默认情况下它是如何工作的,但答案可能就在新的标准文档中:

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html

【讨论】:

    【解决方案3】:

    C++0x 论文N2427(原子)大致陈述如下。我稍微改变了措辞,以便更容易阅读具体的减量情况,我改变的部分是粗体

    效果: 将 object 中的 value 原子替换为 object 中的 value 应用 decrement 的结果em> 和给定的操作数。内存按顺序受影响。这些操作在 [N2334 或后续添加的新部分] 中的“同步于”定义的意义上是读-修改-写操作,因此这样的操作和产生输入值的评估都与任何评估同步读取更新的值。

    返回: object 的值在 decrement 之前的原子值。

    原子操作保证递减运算符将返回变量在操作之前立即保存的值,这是原子的,因此不会有来自另一个线程更新的中间值。

    这意味着以下是唯一此代码可能执行的 2 个线程:

    (Initial Value: 1)
    Thread 1: Decrement 
    Thread 1: Compare, value is 0, enter region of interest
    Thread 2: Decrement
    Thread 2: Compare, value is -1, don't enter region
    

    (Initial Value: 1)
    Thread 1: Decrement 
    Thread 2: Decrement
    Thread 1: Compare, value is 0, enter region of interest
    Thread 2: Compare, value is -1, don't enter region
    

    案例 1 是无趣的预期案例。

    情况 2 交错递减操作并稍后执行比较操作。因为递减取操作是原子的,所以线程1不可能接收到0以外的值进行比较。它无法收到-1,因为操作是原子的...读取发生在递减时,不是在比较时。更多线程不会改变这种行为。

    【讨论】:

    • 请注意,我检查了 N3291,虽然它使用不同的措辞,但它同意这一点。
    • 这对于 " --myint; if(myint == 0) { }" 仍然正确吗?
    • @paulm 如果您递减并签入两个不同的语句,这绝对不是真的。必须在同一个语句中完成。
    猜你喜欢
    • 1970-01-01
    • 2020-03-06
    • 2022-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-23
    • 1970-01-01
    相关资源
    最近更新 更多