C语言 是不同的原子操作(例如:__sync_fetch_and_add和__sync_lock_test_and_set



我正在学习硬件支持的原子操作。我知道有很多原子操作,例如,比较和交换(CAS),获取和添加(FAA),测试和设置。

我明白,当我们在多线程程序的共享资源上只使用一个原子操作时,不同的线程可以互斥地访问共享资源。例如:

// this code implements a spinlock with CAS
void lock_init(int *lock){
*lock = 0;
}
void lock(int *lock) {
while(__sync_val_compare_and_swap(lock, 0, 1) != 0) {
; // busy-looping
}
}
void unlock(int *lock) {
*lock = 0;
}

在上面的代码中,所有访问锁变量的线程都将使用CAS原子操作来互斥地操作锁变量。

然而,当我们在同一个变量上使用多个不同的原子操作时,这些不同的原子操作是否可以相互排斥地访问共享变量?

以以下代码为例:

template<typename T> 
class AtomicIntegerT
{
public:
AtomicIntegerT()
: value_(0) 
{
}

T get() {
return __sync_val_compare_and_swap(&value_, 0, 0);
}   
T getAndAdd(T x) {
return __sync_fetch_and_add(&value_, x);
}
T addAndGet(T x) {
return getAndAdd(x) + x;
}
T getAndSet(T newValue) {
return __sync_lock_test_and_set(&value_, newValue);
}
private:
volatile T value_; 
};

我想实现原子变量__sync_val_compare_and_swap, __sync_fetch_and_add, __sync_lock_test_and_set。使用__sync_val_compare_and_swap获取变量的值;使用__sync_fetch_and_add为变量添加一些值;使用__sync_lock_test_and_set实现原子赋值操作。

当一个线程正在执行getAndSet()而另一个线程正在执行getAndAdd(),这两个线程可以访问value_互斥吗?

更普遍的问题是不同的原子操作(例如:__sync_fetch_and_add和__sync_lock_test_and_set)互斥吗?

是的,已弃用的GNU C__sync内置和现代GNU C__atomic内置都是对象上的原子操作。您可以在不同的线程中使用两个不同的原子操作,并获得一致的结果。

多个线程可以并行__atomic_load_n,纯负载之间不需要互斥。你的get会更有效,而不是__syncCAS与0,0!

但除此之外,__sync__atomic是等价互斥的,就对该对象的操作而言。已弃用的遗留__sync内置也相当于作为操作的一部分的完整屏障(与atomic_thread_fence(memory_order_seq_cst)一样,而不仅仅是seq_cst操作),因此它们可能会创建类似互斥的同步。

__atomic对不同对象的顺序弱于__ATOMIC_SEQ_CST的操作可以出现重叠,但每个操作仍然是原子的。

__atomic的内置是<atomic>用来实现std::atomic<T>在c++中使用的。在C中,<stdatomic.h>_Atomic是使用与__atomic内置相同功能的可移植方式。(除了ISO C没有办法在程序的某些部分对对象进行非原子访问,并且只有在多线程部分才进行原子访问。c++ 20std::atomic_ref<>可以做到这一点,或者您可以在GNU C中使用__atomic内置功能。

最新更新