GNU C++中的原子交换

Ste*_*eve 18 c++ g++ atomic atomic-swap

我想验证我的理解是否正确.这种事情很棘手,所以我几乎可以肯定我错过了什么.我有一个由实时线程和非实时线程组成的程序.我希望非RT线程能够将指针交换到RT线程使用的内存.

从文档中,我的理解是,这可以通过以下方式实现g++:

// global
Data *rt_data;

Data *swap_data(Data *new_data)
{
#ifdef __GNUC__
    // Atomic pointer swap.
    Data *old_d = __sync_lock_test_and_set(&rt_data, new_data);
#else
    // Non-atomic, cross your fingers.                                          
    Data *old_d = rt_data;
    rt_data = new_data;
#endif
    return old_d;
}
Run Code Online (Sandbox Code Playgroud)

这是程序中唯一rt_data被修改的地方(初始设置除外).当rt_data在实时上下文中使用,它被复制到本地指针.对于old_d以后,当确定未使用旧内存时,它将在非RT线程中释放.它是否正确?我需要volatile在任何地方吗?我应该调用其他同步原语吗?

顺便说一下,我在C++中这样做,虽然我对C的答案是否不同感兴趣

提前谢谢.

def*_*ode 25

一般volatile在编写并发代码时不要使用C/C++.语义volatile是如此接近你想要的它是诱人的但最终挥发性是不够的.不幸的是Java/C# volatile != C/C++ volatile.Herb Sutter有一篇很棒的文章解释了令人困惑的混乱.

你真正想要的是记忆围栏. __sync_lock_test_and_set为您提供围栏.

将rt_data指针复制(加载)到本地副本时,还需要一个内存栏.

无锁编程很棘手.如果你愿意使用Gcc的c ++ 0x扩展,那就更简单了:

#include <cstdatomic>

std::atomic<Data*> rt_data;

Data* swap_data( Data* new_data )
{
   Data* old_data = rt_data.exchange(new_data);
   assert( old_data != new_data );
   return old_data;
}

void use_data( )
{
   Data* local = rt_data.load();
   /* ... */
}
Run Code Online (Sandbox Code Playgroud)