GNU C++ 中的原子交换 [英] Atomic swap in GNU C++
问题描述
我想验证我的理解是否正确.这种事情很棘手,所以我几乎可以肯定我错过了一些东西.我有一个由实时线程和非实时线程组成的程序.我希望非 RT 线程能够交换指向 RT 线程使用的内存的指针.
I want to verify that my understanding is correct. This kind of thing is tricky so I'm almost sure I am missing something. I have a program consisting of a real-time thread and a non-real-time thread. I want the non-RT thread to be able to swap a pointer to memory that is used by the RT thread.
从文档中,我的理解是这可以在 g++
中使用:
From the docs, my understanding is that this can be accomplished in g++
with:
// 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;
}
这是程序中唯一修改rt_data
的地方(初始设置除外).当 rt_data
在实时上下文中使用时,它被复制到本地指针.对于old_d
,稍后当确定没有使用旧内存时,将在非RT线程中释放它.这样对吗?我在任何地方都需要 volatile
吗?我应该调用其他同步原语吗?
This is the only place in the program (other than initial setup) where rt_data
is modified. When rt_data
is used in the real-time context, it is copied to a local pointer. For old_d
, later on when it is sure that the old memory is not used, it will be freed in the non-RT thread. Is this correct? Do I need volatile
anywhere? Are there other synchronization primitives I should be calling?
顺便说一下,我是用 C++ 做这件事的,尽管我对 C 的答案是否不同很感兴趣.
By the way I am doing this in C++, although I'm interested in whether the answer differs for C.
提前致谢.
推荐答案
在C/C++
中编写并发代码时,一般不要使用volatile
.volatile
的语义非常接近你想要的,它很诱人,但最终 volatile 是 不够.不幸的是Java/C# volatile != C/C++ volatile
.Herb Sutter 有一篇很棒的文章解释了一团糟.
Generally don't use volatile
when writing concurrent code in C/C++
. The semantics of volatile
are so close to what you want that it is tempting but in the end volatile is not enough. Unfortunately Java/C# volatile != C/C++ volatile
. Herb Sutter has a great article explaining the confusing mess.
您真正想要的是内存栅栏.__sync_lock_test_and_set
为您提供围栏.
What you really want is a memory fence. __sync_lock_test_and_set
provides the fencing for you.
当您将 rt_data 指针复制(加载)到本地副本时,您还需要一个内存栅栏.
You will also need a memory fence when you copy (load) the rt_data pointer to your local copy.
无锁编程很棘手.如果你愿意使用 Gcc 的 c++0x 扩展,那就简单一点:
Lock free programming is tricky. If you're willing to use Gcc's c++0x extensions, it's a bit easier:
#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();
/* ... */
}
这篇关于GNU C++ 中的原子交换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!