std :: atomic_store和std :: atomic_exchange不交换

时间:2016-01-28 22:17:18

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

根据en.cppreference.comstd::atomic_exchangestd::atomic_store相当于线程安全std::swap。但这不是我用g ++或clang ++获得的行为。

Problem live on coliru.(见下文)

它打印了这个:

std::atomic_store

a: 0x1ed2c30    0
b: 0x1ed2c50    1

a: 0x1ed2c50    1
b: 0x1ed2c50    1

std::atomic_exchange

a: 0x1ed2c50    0
b: 0x1ed2c30    1

a: 0x1ed2c30    1
b: 0x1ed2c30    1

这是为什么?难道我做错了什么?我误读了文档吗?

代码清单

#include <iostream>
#include <memory>

int main()
{
    {
        std::cout << "std::atomic_store\n\n";
        auto a = std::make_shared<int>(0);
        auto b = std::make_shared<int>(1);

        std::cout
        << "a: " << a.get() << '\t' << *a << '\n'
        << "b: " << b.get() << '\t' << *b << '\n' << std::endl;

        std::atomic_store(&a, b);

        std::cout
        << "a: " << a.get() << '\t' << *a << '\n'
        << "b: " << b.get() << '\t' << *b << '\n' << std::endl;
    }
    {
        std::cout << "std::atomic_exchange\n\n";
        auto a = std::make_shared<int>(0);
        auto b = std::make_shared<int>(1);

        std::cout
        << "a: " << a.get() << '\t' << *a << '\n'
        << "b: " << b.get() << '\t' << *b << '\n' << std::endl;

        std::atomic_exchange(&a, b);

        std::cout
        << "a: " << a.get() << '\t' << *a << '\n'
        << "b: " << b.get() << '\t' << *b << '\n' << std::endl;
    }
}

4 个答案:

答案 0 :(得分:11)

这种描述有点误导。

它说,例如,

template<class T>
void atomic_store( std::shared_ptr<T>* p,
                   std::shared_ptr<T> r );

“有效”会p->swap(r)。这一点确实如此(实际上标准也是如此)。

但是,r是一个由值传递的函数参数,因此在函数返回之前被销毁。它不会影响调用者中的任何内容。

答案 1 :(得分:2)

std::atomic_exchange不交换a和b,它将a设置为b并返回a的前一个值。

你可以这样做:

b = std::atomic_exchange(&a, b);

这将按预期工作(交换a和b的指针),但这不是线程安全的:如果多个线程同时访问对象b,则这是未定义的行为。你不能做得更好,因为共享指针是一个复杂的结构,通常包含两个数据成员(两个指针)。由于无原子锁定交换需要硬件支持,因此仅适用于基本类型(整数和指针)。

答案 2 :(得分:1)

令我困惑的是,为什么“比较和交换”&#39;其中有swap个。它不会交换任何东西。它设置check passess时的值,如果检查失败则返回当前值。因此,绝不是atomic_exchange与std :: swap相同。

相反,它是一种检查和设置模式,所以我总是喜欢CAS来表示比较和设置。

答案 3 :(得分:0)

看起来我想要的行为最接近的是:

    std::atomic_store(
        &b,
        std::atomic_exchange(
            &a,
            b
        )
    );

然而,这不是严格的原子。 ab可以在几分之一秒内指向相同的地址。

在我的情况下,只要这两种行为都指向有效的,定义良好的对象,这种行为是可以接受的。