将volatile数据与不为volatile数据重载的方法一起使用

时间:2013-08-29 09:09:38

标签: c++ gcc shared-memory systemc

我的知识结束了。

我有三个进程通过共享内存段进行通信。并发访问是通过正确的锁定来处理的(为了避免在这里被误解),所以我很确定我正在按照预期的方式使用volatile关键字。

我的共享内存段被强制转换为指向结构的易失性指针,我可以对此进行操作。结构必须是易失性的,因为我有时需要旋转直到共享内存上的某个值发生变化 - 所以不使用volatile不是一种选择。

现在我正在使用外部C ++库(SystemC,但这不应该重要),我的struct包含sc_time的成员。虽然我可以访问该库的源代码,但我不想依赖于我所做的修改,可能会破坏内容或进入维护地狱。

现在这个类“sc_time”包含用于比较和赋值的运算符。这些运算符不适用于volatile sc_time - 到目前为止并不令人惊讶。

现在我的问题是:有没有办法在不破坏语义的情况下转换掉这种易变性?我可以使用经常提到的const_cast<>或简单的C-cast,但编译器会做什么呢?我甚至可能只是memcpy()数据 - 但是再一次,结果会是什么?

任何建议都会受到欢迎 - 我会毫无问题地使用只有C的包装器或任何其他方法 - 只要它工作(tm),但我的最后一种方法是使用类似memcpy的小型汇编程序代码真正阅读数据 - 这是我想避免的。

感谢您抽出时间阅读本文: - )

编辑:添加了小代码段:

struct shared_memory{
     sc_time time1;
     sc_time time2;
     sc_time time3;
     ...
}

...

class foo 
{
    foo();   // attach shared memory and assign to *mem
    ...
    pthread_mutex_t mutex;
    volatile struct shared_memory *mem;
    ...
    void do_stuff();  // periodically called
};

void foo::do_stuff()
{
   ...
   lock_mutex(mutex);
   sc_time t1 = mem->time1;
   sc_time t2 = mem->time2;
   sc_time t3 = mem->time3;
   unlock_mutex(mutex);
   ... 
   while(t1 < t2 || t1 < t3){
       lock_mutex(mutex);
       t1 = mem->time1;
       t2 = mem->time2;
       t3 = mem->time3;
       unlock_mutex(mutex);
   }

}

2 个答案:

答案 0 :(得分:2)

如果您必须旋转等待变量的更改,则正确锁定。旋转等待总是必须假定对数据的原子访问。这不仅仅是关于获取最新版本的数据,这也是关于一致性,例如,数据可能会分成几个缓存行,您可能只获得旧版本的低字节和更新版本的高字节。

出于这个原因,新的C和C ++标准具有用于原子访问的概念和工具,如果可能的话,使用它们。如果您没有它们,请使用编译器(或库)扩展:所有现代处理器都有原子指令,任何体面的编译器都有一个提供此类功能的扩展。

使用volatile玩游戏不是您应该去的路径。如果抛弃volatile并将这样的对象传递给不希望在其下发生变化的函数,所有事情都可能发生。特别是,当没有volatile的库被编译时,可以执行破坏数据的优化。不要这样做。

编辑:由于您还使用gcc标记了您的问题,因为他们有充足的__sync_lock_test_and_set个内置版,因为它是一个漫长的时间作为扩展。用它。也许在你特定的架构组合中,这将解决完全相同的代码,但相信gcc的人,他们知道什么时候他们必须添加一些汇编魔术来保证你的数据。

答案 1 :(得分:0)

你可以使用const_cast来消除变量的'volatile'和'const'。

注意:编译器将函数中的变量视为非易失性:)

相关问题