C++ 使用gcc原子内置的原子交换函数
这是通用原子交换函数的正确实现吗?我正在寻找一个在GCC上兼容C++03的解决方案C++ 使用gcc原子内置的原子交换函数,c++,atomic,C++,Atomic,这是通用原子交换函数的正确实现吗?我正在寻找一个在GCC上兼容C++03的解决方案 template<typename T> void atomic_swap(T & a, T & b) { static_assert(sizeof(T) <= sizeof(void*), "Maximum size type exceeded."); T * ptr = &a; b =__sync_lock_test_and_set(ptr,
template<typename T>
void atomic_swap(T & a, T & b) {
static_assert(sizeof(T) <= sizeof(void*), "Maximum size type exceeded.");
T * ptr = &a;
b =__sync_lock_test_and_set(ptr, b);
__sync_lock_release(&ptr);
}
PS:是一个类似的问题,但它没有回答我的问题,因为提供的答案需要C++11的
std::atomic
,并且它有签名Data*swap\u Data(Data*new\u Data)
,这对于swap
函数来说似乎毫无意义。(它实际上将提供的参数与函数之前定义的全局变量进行交换。)请记住,此版本的交换不是完全原子操作。当b
的值将自动复制到a
中时,a
的值可以通过另一个线程对b
的值进行另一次修改。换句话说,b
的赋值相对于其他线程来说不是原子的。因此,您可能会遇到这样的情况:a==1
和b==2
,在gcc内置之后,您会得到a==2
并返回1
的值,但现在另一个线程已将b
的值更改为3
,然后用1
的值在b
中写入该值。因此,虽然您可能已经“从技术上”交换了这些值,但您并没有以原子方式进行交换。。。另一个线程在从gcc原子内置返回和将该返回值分配给b
之间触及了b
的值。从组装的角度来看,您有如下情况:
lea RAX, qword ptr [RDI] // T * ptr = &a;
mov RCX, qword ptr [RSI] // copy out the value referenced by b into a register
xchg [RAX], RCX // __sync_lock_test_and_set(&a, b)
mov qword ptr [RSI], RCX // place the exchange value back into b (not atomic!!)
老实说,如果没有像DCAS或弱负载链接/存储条件这样的硬件操作,或者可能使用像事务性内存(其本身倾向于使用细粒度锁定)这样的其他方法,就无法对两个单独的内存位置进行无锁原子交换
其次,由于您的函数现在已经编写完毕,如果您希望原子操作同时具有获取和释放语义,那么是的,您必须将其放置在
\uuuu sync\u lock\u release
中,或者必须通过\uu sync\u synchronize
添加一个完整的内存屏障。否则,它将仅在\uuuu同步\u锁定\u测试\u和\u集上具有acquire语义。尽管如此,它并没有自动地交换两个独立的内存位置……看起来只有对a
的访问才应该是原子的?为什么要重新发明一个轮子?看看@BenVoigt,这篇文章没有给出明确的答案。它用一个全局变量交换参数。我知道写入b
使它成为一个非原子操作,因此不是线程安全的。然而,我看不到一种安全的方法。这是否意味着指针类型的无锁交换实际上是不可能的?除非硬件支持DCAS或负载链接/存储条件操作之类的操作,该操作相当弱,因此如果对内存有任何访问,或至少对缓存线有内存访问,则会失败,您要交换的两个值位于同一缓存线上
lea RAX, qword ptr [RDI] // T * ptr = &a;
mov RCX, qword ptr [RSI] // copy out the value referenced by b into a register
xchg [RAX], RCX // __sync_lock_test_and_set(&a, b)
mov qword ptr [RSI], RCX // place the exchange value back into b (not atomic!!)