我的知识结束了。
我有三个进程通过共享内存段进行通信。并发访问是通过正确的锁定来处理的(为了避免在这里被误解),所以我很确定我正在按照预期的方式使用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);
}
}
答案 0 :(得分:2)
如果您必须旋转等待变量的更改,则不正确锁定。旋转等待总是必须假定对数据的原子访问。这不仅仅是关于获取最新版本的数据,这也是关于一致性,例如,数据可能会分成几个缓存行,您可能只获得旧版本的低字节和更新版本的高字节。
出于这个原因,新的C和C ++标准具有用于原子访问的概念和工具,如果可能的话,使用它们。如果您没有它们,请使用编译器(或库)扩展:所有现代处理器都有原子指令,任何体面的编译器都有一个提供此类功能的扩展。
使用volatile
玩游戏不是您应该去的路径。如果抛弃volatile
并将这样的对象传递给不希望在其下发生变化的函数,所有事情都可能发生。特别是,当没有volatile
的库被编译时,可以执行破坏数据的优化。不要这样做。
编辑:由于您还使用gcc标记了您的问题,因为他们有充足的__sync_lock_test_and_set
个内置版,因为它是一个漫长的时间作为扩展。用它。也许在你特定的架构组合中,这将解决完全相同的代码,但相信gcc的人,他们知道什么时候他们必须添加一些汇编魔术来保证你的数据。
答案 1 :(得分:0)
你可以使用const_cast来消除变量的'volatile'和'const'。
注意:编译器将函数中的变量视为非易失性:)