Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/151.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用gcc原子内置的原子交换函数_C++_Atomic - Fatal编程技术网

C++ 使用gcc原子内置的原子交换函数

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,

这是通用原子交换函数的正确实现吗?我正在寻找一个在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, 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!!)