c – 互斥体的存在有助于摆脱挥发性关键词吗?

前端之家收集整理的这篇文章主要介绍了c – 互斥体的存在有助于摆脱挥发性关键词吗?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个多R / W锁类,可以保持读,写和待处理读取等待写入计数器.互斥体从多个线程中保护它们.

我的问题是,我们仍然需要将这些计数器声明为volatile,以便编译器在进行优化时不会使其松动.

或者编译器考虑到计数器被互斥体保护.

我明白互斥是用于同步的运行时机制,“volatile”关键字是一个编译时指示,编译器在进行优化时做正确的操作.

问候,
-Jay.

解决方法

这里有两个基本上无关的项目,总是困惑.

>挥发性
线程,锁,内存障碍等

volatile用于告诉编译器生成代码以从内存中读取变量,而不是从寄存器读取变量.并且不要重新排序代码.一般来说,不优化或采取“快捷”.

内存障碍(由互斥锁,锁等提供)在Herb Sutter引用另一个答案中,是为了防止cpu重新排序读/写存储器请求,而不管编译器如何做.即不要优化,不要采取快捷方式 – 在cpu级别.

类似的,但实际上是非常不同的事情.

在你的情况下,在大多数锁定情况下,volatile不是必需的,这是因为为了锁定而进行的函数调用.即:

正常功能调用影响优化:

external void library_func(); // from some external library

global int x;

int f()
{
   x = 2;
   library_func();
   return x; // x is reloaded because it may have changed
}

除非编译器可以检查library_func()并确定它不触及x,否则它将在返回时重新读取x.这甚至没有波动.

线程:

int f(SomeObject & obj)
{
   int temp1;
   int temp2;
   int temp3;

   int temp1 = obj.x;

   lock(obj.mutex); // really should use RAII
      temp2 = obj.x;
      temp3 = obj.x;
   unlock(obj.mutex);

   return temp;
}

在读取obj.x for temp1之后,编译器将重新读取temp2的obj.x – 不是因为锁的魔力 – 而是因为不确定lock()是否被修改为obj.您可以设置编译器标志来积极地优化(无别名等),因此不会重新读取x,但是一堆代码可能会开始失败.

对于temp3,编译器(希望)不会重新读取obj.x.
如果由于某种原因,obj.x可能在temp2和temp3之间改变,那么您将使用volatile(并且您的锁定将被破坏/无用).

最后,如果你的lock()/ unlock()函数以某种方式内联,也许编译器可以评估代码,看到obj.x没有被改变.但是我保证这里有两件事情之一:
– 内联代码最终会调用一些操作系统级锁定功能(从而防止评估)或
– 您调用一些asm内存屏障指令(即包装在__InterlockedCompareExchange中的内联函数),您的编译器将会识别,从而避免重新排序.

编辑:我忘了提到 – 对于pthreads的东西,一些编译器被标记为“POSIX兼容”,这意味着,除了别的以外,它们将会识别pthread_函数,而不会对它们进行不好的优化.即使C标准尚未提到线程,那些编译器(至少最低限度)也是这样.

所以,简短的回答

你不需要挥发性.

猜你在找的C&C++相关文章