我正在学习硬件支持的原子操作,我知道有很多原子操作,例如,比较和交换(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_fetch_and_add在变量上添加某个值;使用__sync_lock_test_and_set实现原子赋值操作。
当一个线程正在执行getAndSet(),而另一个线程正在执行getAndAdd()时,这两个线程是否可以互斥地访问value?
更普遍的问题是,不同的原子操作(例如,__sync_fetch_and_add和__sync_lock_test_and_set)是互斥的吗?
1条答案
按热度按时间x4shl7ld1#
是的,被弃用的GNU C
__sync
内置函数和modern GNU C__atomic
builtins都是对象上的原子操作。您可以从不同的线程使用两个不同的原子操作,并获得一致的结果。多个线程可以并行执行
__atomic_load_n
,在纯负载之间不需要互斥。这样你的get
会比__sync
CAS和0,0
更有效率!但是,
__sync
和__atomic
内置函数在对象上的操作是等价的互斥。过时的旧版__sync
内置函数也等价于作为操作一部分的完整barrier(如atomic_thread_fence(memory_order_seq_cst)
,而不仅仅是seq_cst operation),因此它们可能会创建类似互斥的同步。在不同对象上具有弱于
__ATOMIC_SEQ_CST
的顺序的__atomic
操作可以看起来重叠,但是每个操作仍然是原子的。__atomic
内置函数是<atomic>
用来实现std::atomic<T>
在C中使用的函数。在C中,<stdatomic.h>
和_Atomic
是使用与__atomic
内置函数相同功能的可移植方式。(除了ISO C没有办法在程序的某些部分对对象进行非原子访问之外,C20std::atomic_ref<>
就可以做到这一点,或者你也可以在GNU C中使用__atomic
内置函数。)