大于CPU原生支持的原子如何工作

Edi*_*tis 11 c++ c++11 stdatomic

使用当前的 C++ 编译器,您可以获得比 CPU 实际支持更大的原子支持。使用 x64,您可以拥有 16 字节的原子,但 std::atomic 也适用于更大的元组。看这段代码:

#include <iostream>
#include <atomic>

using namespace std;

struct S { size_t a, b, c; };

atomic<S> apss;

int main()
{
    auto ref = apss.load( memory_order_relaxed );
    apss.compare_exchange_weak( ref, { 123, 456, 789 } );
    cout << sizeof ::apss << endl;
}
Run Code Online (Sandbox Code Playgroud)

对于我的平台,上面的 cout 总是打印 32。但是,如果没有互斥体,这些事务实际上是如何工作的呢?我从检查拆卸中没有得到任何线索。

如果我使用 MSVC++ 运行以下代码:

#include <atomic>
#include <thread>
#include <array>

using namespace std;

struct S { size_t a, b, c, d, e; };

atomic<S> apss;

int main()
{
    array<jthread, 2> threads;
    auto threadFn = []()
    {
        auto ref = apss.load( memory_order_relaxed );
        for( size_t i = 10'000'000; i--; apss.compare_exchange_weak( ref, { } ) );
    };
    threads[0] = jthread( threadFn );
    threads[1] = jthread( threadFn );
}
Run Code Online (Sandbox Code Playgroud)

代码几乎不消耗内核时间。所以争用实际上完全发生在用户空间中。我猜这是某种软件事务内存发生在这里。

dor*_*ron 3

如果没有机器代码原语来执行没有锁的操作,std::atomic 将添加所需的锁以确保事物是原子的。

甚至还有一个编译时间is_always_lock_free成员可以用来测试这一点。

这在互斥体不能像信号处理程序一样使用的上下文中非常重要。

编辑:值得补充的是,一个好的锁定机制将在用户空间中使用原子,并且仅在存在争用时才遵循内核。Linuxfutex上的 就是这样一种机制。这用于 Linux 上的互斥体。