3

我有点了解我的知识。

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

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

现在我正在使用一个外部 C++ 库(SystemC,但这在这里无关紧要),我的结构从中包含 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);
   }

}
4

2 回答 2

2

如果您必须旋转等待变量的更改,则说明您没有正确锁定。自旋等待总是必须假设对数据的原子访问。这不仅与获取最新版本的数据有关,还与一致性有关,例如,数据可能会被拆分到多个缓存行中,并且您可能只获取旧版本的低字节和更新版本的高字节。

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

玩游戏volatile不是你应该走的路。如果你抛弃 avolatile并将这样的对象传递给一个不期望在它下面发生变化的函数,那么所有事情都可能发生。特别是,当没有volatile编译的库时,可以执行破坏数据的优化。不要这样做。

编辑:由于您还使用 gcc 标记了您的问题,因此他们有一个很好的理由,因为他们在__sync_lock_test_and_set很长一段时间以来就已经内置了作为扩展。用它。也许在您特定的架构组合上,这将在完全相同的代码中解决,但请相信 gcc 人员,他们知道何时必须添加一些汇编程序魔术来为您提供有关数据的保证。

于 2013-08-29T09:48:56.343 回答
0

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

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

于 2013-08-29T09:28:26.017 回答