题
我想验证我的理解是正确的。这种事情很棘手,所以我几乎可以肯定,我失去了一些东西。我有由实时线程和非实时线程的程序。我想非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;
}
这是在rt_data
被修改的程序(比初始设置其他)的唯一地方。当rt_data
在实时环境中使用,它被复制到本地指针。对于old_d
,后来就当它是确保旧内存不使用时,它会在非实时线程释放。这个对吗?我需要volatile
地方?是否有其他的同步原语我要打电话?
,通过我在C ++这样的方式虽然我感兴趣的答案不同,是否对C。
由于时间提前。
解决方案
在volatile
编写并发代码时一般不要用C/C++
。 volatile
的语义是如此接近你想要的东西,这是诱人的,但到底是挥发性的不够。不幸的是Java/C# volatile != C/C++ volatile
。香草萨特有一个伟大的文章解释混乱的混乱。
你真正想要的是一个存储栅栏。 __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();
/* ... */
}
其他提示
更新:这个答案是不正确的,因为我错过了一个事实,即访问volatile
变量volatile
保证不会重新排序,但不提供这种保证相对于其他非volatile
访问和操作。内存栅栏确实提供了这样的保证,这需要这种应用。我原来的答案是低于,但不采取行动。请参见这个答案用于在我的理解是导致以下不正确的响应中的孔中的很好的解释。
原来的答复:
是的,你需要在你的volatile
声明rt_data
;的任何时间的变量可以一个线程的控制流之外进行修改访问它,但是应当声明volatile
即可。虽然你可以逃脱不volatile
因为你复制到本地指针,volatile
至少有帮助的文档,也抑制了一些编译器优化可能会导致问题。考虑下面的例子,从 DDJ 通过:
volatile int a;
int b;
a = 1;
b = a;
如果有可能a
具有a=1
和b=a
之间它的值发生变化,则a
应声明volatile
(除非,当然,分配外的日期的值,以b
是可接受的)。多线程,特别是与原子基元,构成这样的情况。的情况也与由信号处理程序修改的变量,并通过映射到奇数存储器位置变量触发(例如硬件I / O寄存器)。还参见这个问题。
否则,它看起来好像没什么问题。
在C,I可能会使用通过 GLib的此提供的原子基元。他们将使用一个原子操作,其中可用,回落到一个缓慢但正确的基于互斥的实现,如果原子操作不可用。升压可提供C ++类似的东西。