简体   繁体   English

std::atomic_ref 如何为非原子类型实现?

[英]How is std::atomic_ref implemented for non-atomic types?

I am wondering how can std::atomic_ref be implemented efficiently (one std::mutex per object) for non-atomic objects as the following property seems rather hard to enforce:我想知道如何为非原子对象有效地实现std::atomic_ref (每个对象一个std::mutex ),因为以下属性似乎很难强制执行:

Atomic operations applied to an object through an atomic_ref are atomic with respect to atomic operations applied through any other atomic_ref referencing the same object.通过 atomic_ref 应用于 object 的原子操作相对于通过引用相同 object 的任何其他 atomic_ref 应用的原子操作而言是原子操作。

In particular, the following code:特别是以下代码:

void set(std::vector<Big> &objs, size_t i, const Big &val) {
    std::atomic_ref RefI{objs[i]};
    RefI.store(val);
}

Seems quite difficult to implement as the std::atomic_ref would need to somehow pick every time the same std::mutex (unless it is a big master lock shared by all objects of the same type).似乎很难实现,因为std::atomic_ref都需要以某种方式选择相同的std::mutex (除非它是同一类型的所有对象共享的大主锁)。

Am I missing something?我错过了什么吗? Or each object is responsible to implement std::atomic_ref and therefore either be atomic or carry a std::mutex ?或者每个 object 负责实现std::atomic_ref ,因此要么是原子的,要么带有std::mutex

An implementation can use a hash based on the address of the object to determine which of a set of locks to acquire while performing the operation.实现可以使用 hash 基于 object 的地址来确定在执行操作时要获取一组锁中的哪一个。

The implementation is pretty much exactly the same as std::atomic<T> itself.实现与std::atomic<T>本身几乎完全相同 This is not a new problem.这不是一个新问题。

See Where is the lock for a std::atomic?请参阅std::atomic 的锁在哪里? A typical implementation of std::atomic / std::atomic_ref a static hash table of locks, indexed by address, for non-lock-free objects. std::atomic / std::atomic_ref的典型实现是 static hash 锁表,按地址索引,用于非无锁对象。 Hash collisions only lead to extra contention, not a correctness problem. Hash 冲突只会导致额外的争用,而不是正确性问题。 (Deadlocks are still impossible; the locks are only used by atomic functions which never try to take 2 at a time.) (死锁仍然是不可能的;锁只被原子函数使用,它们从不尝试一次取 2 个。)

On GCC for example, std::atomic_ref is just another way to invoke __atomic_store on an object.例如,在 GCC 上, std::atomic_ref只是在 object 上调用__atomic_store的另一种方式。 (See the GCC manual: atomic builtins ) (参见GCC 手册:atomic builtins

The compiler knows whether T is small enough to be lock-free or not.编译器知道T是否小到可以无锁。 If not, it calls the libatomic library function which will use the lock.如果没有,它会调用将使用锁的 libatomic 库 function。

(fun fact: that means it only works if the object has sufficient alignment for atomic<T> . But on many 32-bit platforms including x86, uint64_t might only have 4-byte alignment. atomic_ref on such an object will compile and run, but not actually be atomic if the compiler uses an SSE 8-byte load/store in 32-bit mode to implement it. Fortunately there's no danger for objects that have alignof(T) == sizeof(T) , like most primitive types on 64-bit architectures.) (fun fact: that means it only works if the object has sufficient alignment for atomic<T> . But on many 32-bit platforms including x86, uint64_t might only have 4-byte alignment. atomic_ref on such an object will compile and run,但如果编译器在 32 位模式下使用 SSE 8 字节加载/存储来实现它,则实际上不是原子的。幸运的是,具有alignof(T) == sizeof(T)的对象没有危险,就像大多数原始类型一样64 位架构。)

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

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