繁体   English   中英

不要真正理解 std::atomic::compare_exchange_weak 和 compare_exchange_strong 的逻辑

[英]Don't really get the logic of std::atomic::compare_exchange_weak and compare_exchange_strong

我读过https://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange

原子地比较 *this 的 object 表示(C++20 前)值表示(C++20 起)与预期的,如果它们按位相等,则将前者替换为所需的(执行读-修改-写操作)。 否则,将存储在 *this 中的实际值加载到预期中(执行加载操作)。

所以我理解的代码就像

bool expected=true;
extern atomic<bool> b = false; 
void foo ()
{
//
    while(!b.compare_exchange_weak(expected, false));
//
}

在循环运行一次(忽略虚假失败)之后,它将失败,并将写入预期的false ,因此在第二次迭代中 compare_exchange_weak 将返回成功,尽管b尚未更改为 true。 但这一切的意义何在? 我虽然可以将它用作同步锁,等待其他线程更改b ,但现在我想不出这个的用法。

cppreference 中的示例还显示,在两次调用之后 compare_exchange_strong 将成功。

#include <atomic>
#include <iostream>
 
std::atomic<int>  ai;
 
int  tst_val= 4;
int  new_val= 5;
bool exchanged= false;
 
void valsout()
{
    std::cout << "ai= " << ai
          << "  tst_val= " << tst_val
          << "  new_val= " << new_val
          << "  exchanged= " << std::boolalpha << exchanged
          << "\n";
}
 
int main()
{
    ai= 3;
    valsout();
 
    // tst_val != ai   ==>  tst_val is modified
    exchanged= ai.compare_exchange_strong( tst_val, new_val );
    valsout();
 
    // tst_val == ai   ==>  ai is modified
    exchanged= ai.compare_exchange_strong( tst_val, new_val );
    valsout();
}

结果:

ai= 3  tst_val= 4  new_val= 5  exchanged= false
ai= 3  tst_val= 3  new_val= 5  exchanged= false
ai= 5  tst_val= 3  new_val= 5  exchanged= true

我将举一个我确实使用过的例子,因为它非常简单。

我有 atomic ,它描述了某些东西的可用大小。 integer 存在溢出的危险,所以我在减去一个值之前先进行检查。

不是我的生产代码的精确复制粘贴:

class LockFreeCuncuretSizeLimit {
public:
    explicit LockFreeCuncuretSizeLimit(size_t available) : mSize{available}
    {}

    bool tryAcuqire(size_t s) {
        size_t lastSize = mSize;
        size_t newSize;
        do
        {
            if (lastSize >= s)
            {
                newSize = lastSize - s;
            }
            else
            {
                return false;
            }

        }
        while (!mSize.compare_exchange_weak(lastSize, newSize));
        return true;
    }

    void release(size_t s) {
        mSize += s; // here I do not have worry about integer overflow
    }
private:
    std::atomic<size_t> mSize;
};

现在尝试 image 在没有compare_exchange_strong并且没有竞争条件的情况下执行此操作。

有一个条件满足的变化,但是当在原子上进行减法时,其他一些线程已经减去了一个值,所以当我进行实际减法时,可能会溢出 integer。 因此,如果没有compare_exchange_strong就无法做到这一点。

现在compare_exchange_strongcompare_exchange_weak之间的区别很难解释。 甚至 Herb Sutter 在一些 cppcon 谈话中也放弃了解释,并提供了简单的规则:“如果你需要循环使用compare_exchange_weak否则使用compare_exchange_strong ”。

std::atomic::compare_exchange_weak以线程感知的方式执行这个英语任务:

因为变量保持expected ,它现在应该保持desired

作为一项微不足道的任务,想象你的std::atomic<int> x的值应该是平方的。 但是其他线程可能正在修改它,因此您不能简单地读取该值,将其平方并写回新值。 可能已经变了!

这是执行此任务的线程安全方式。 您可以保证存储的值将替换为其平方。

int expected = x;
while( !x.compare_exchange_weak(expected, expected*expected) );

除非值已更改,否则此代码将自动用其平方替换expected

如果值已更改,则现在使用新值更新expected ,并且代码会再次尝试。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM