如果volatile对于线程无用,为什么primefaces操作需要指向易失性数据?

我从许多来源读到, volatile关键字 在multithreading场景中 没有帮助 。 但是,这个断言一直受到接受volatile指针的primefaces操作函数的挑战。

例如,在Mac OS X上,我们有OSAtomicfunction系列:

 SInt32 OSIncrementAtomic(volatile SInt32 *address); SInt32 OSDrecrementAtomic(volatile SInt32 *address); SInt32 OSAddAtomic(SInt32 amount, volatile SInt32 *address); // ... 

似乎在Windows上对于Interlocked操作有类似的volatile关键字用法:

 LONG __cdecl InterlockedIncrement(__inout LONG volatile *Addend); LONG __cdecl InterlockedDecrement(__inout LONG volatile *Addend); 

似乎在C ++ 11中,primefaces类型具有使用volatile修饰符的方法,这必然意味着volatile关键字与primefaces性具有某种关系。

那么,我错过了什么? 为什么操作系统供应商和标准库设计者坚持使用volatile关键字进行线程化,如果它没用?

易失性对multithreading的共享访问没有用处 – 只是它不一定足够:

  • 它不一定提供可能需要的内存屏障语义;
  • 它不提供primefaces访问的保证(例如,如果volatile对象大于平台的本机内存字大小)

此外,您还应该注意,示例中API的指针参数上的volatile限定符实际上只增加了API接收指向volatile对象的指针而无需投诉的能力 – 它不要求指针指向实际的volatile对象。 该标准允许非限定指针自动转换为限定指针。 标准中没有提供自动转向(非限定的合格指针)(编译器通常允许它,但发出警告)。

例如,如果InterlockedIncrement()原型为:

 LONG __cdecl InterlockedIncrement(__inout LONG *Addend); // not `volatile*` 

仍然可以实现API以在内部正常工作。 但是,如果用户有一个他希望传递给API的易失性对象,则需要使用强制转换来防止编译器发出警告。

由于(必要或不必要),这些API通常与volatile限定对象一起使用,将volatile限定符添加到指针参数可防止在使用API​​时生成无用的诊断,并且当API与指针一起使用时不会造成任何损害。非易失性物体。

我突然想到我只是误解了volatile*的含义。 就像const*意味着指针对象不应该改变, volatile*意味着指针对象不应该缓存在寄存器中。 这是一个可以自由添加的附加约束:尽可能将char*转换为const char* ,可以将int*转换为volatile int*

因此,将volatile修饰符应用于pointees只是确保primefaces函数可以用于已经volatile变量。 对于非易失性变量,添加限定符是免费的。 我的错误是将原型中关键字的存在解释为使用它的动机,而不是为使用它的人提供便利。

C ++ 11具有volatile和非易失volatile变量的primefaces。

如果编译器内在函数采用指向volatile int的指针,则意味着即使变量是volatile,也可以使用它。 它不会阻止您在非易失volatile数据上使用该function。

好吧,关键字’volatile’确保编译器每次在代码中显示变量时始终从/向内存加载/存储变量的值。
这可以防止某些优化,例如,将值简单地加载到寄存器中一次然后多次使用。
当您有多个线程可以修改线程之间的“共享”变量时,它很有用。 您必须确保始终从/向内存加载/存储值,以便检查其值可以被另一个线程修改。 如果未使用volatile,则其他线程可能没有将新值写入内存(但将其放入寄存器或其他类型的优化可能已经发生)并且第一个线程不会注意到值的任何更改。

在您的情况下,’volatile SInt32 * address’告诉编译器地址指向的内存是任何来源都要更改的主题。 因此需要primefaces操作。