首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >不能真正理解std::atomic::compare_exchange_weak和compare_exchange_strong的逻辑

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

Stack Overflow用户
提问于 2021-03-05 14:03:31
回答 2查看 446关注 0票数 4

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

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

所以,据我所知,代码就像

代码语言:javascript
复制
bool expected=true;
extern atomic<bool> b = false; 
void foo ()
{
//
    while(!b.compare_exchange_weak(expected, false));
//
}

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

Cp首选项中的示例还显示,在两个调用之后,compare_exchange_strong将成功。

代码语言:javascript
复制
#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();
}

结果:

代码语言:javascript
复制
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
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-03-05 14:30:40

我将给出一个例子,因为它非常简单,所以我确实使用了它。

我有原子,它描述了某种东西的可用大小。存在整数溢出的危险,所以我必须先进行检查,然后再减去一个值。

不完全复制我的生产代码:

代码语言:javascript
复制
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;
};

现在,尝试映像,这样做,没有compare_exchange_strong和没有种族条件。

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

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

票数 3
EN

Stack Overflow用户

发布于 2021-03-05 14:40:12

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

,因为变量包含expected,所以它现在应该保存desired

作为一个琐碎的任务,,假设您的std::atomic<int> x的值应该是平方。但是其他线程可能正在修改它,所以您不能简单地读取值、调整值并将新值写回。在你读完它后,它的值可能已经改变了!

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

代码语言:javascript
复制
int expected = x;
while( !x.compare_exchange_weak(expected, expected*expected) );

此代码将原子化地将expected替换为其平方,除非值已更改。

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

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66493926

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档