0

首先,我们有 InterlockedExchange64();

http://msdn.microsoft.com/en-us/library/windows/desktop/ms683593%28v=vs.85%29.aspx

LONGLONG __cdecl InterlockedExchange64( __inout LONGLONG volatile *Target, __in LONGLONG Value );

其次,我们有编译器内在函数 _InterlockedExchange64(),注意没有 volatile;

http://msdn.microsoft.com/en-us/library/1s26w950%28v=vs.80%29.aspx

__int64 _InterlockedExchange64( __int64 * Target, __int64 Value );

接下来,我们有 InterlockedExchangePointer(),它与 ​​InterlockedExchange64() 一样,使用 volatile。

http://msdn.microsoft.com/en-us/library/windows/desktop/ms683609%28v=vs.85%29.aspx

PVOID __cdecl InterlockedExchangePointer( __inout  PVOID volatile *Target, __in PVOID Value );

但是现在我们来到了指针交换的内在函数 _InterlockedExchangePointer() ,在这里我们看到了 volatile 的使用!

http://msdn.microsoft.com/en-us/library/853x471w.aspx

void * _InterlockedExchangePointer( void * volatile * Target, void * Value );

底层指令在所有情况下都是相同的,那么给出了什么?文档错误?

GCC instrincs 没有提到 volatile 进行交换,但是他们也没有提到 CAS !所以这没有帮助。

我的观点是 CAS 目标是易变的,因为你只能在运行时知道交换是否会发生;但是原子交换不应该是易失的,因为目标总是更新的(即使它的值没有改变),所以编译器没有不确定性。

我还看到 InterlockedIncrement() 的函数是易变的,但 instrincs 不是。CAS 的内在函数对于它们的目的地来说是 volatile 的。

4

2 回答 2

3

MSDN 充斥着大多数小的文档错误(例如,__readfsdword仅在 VS 2005 文档下被标记为内核),您真正应该注意的是编译器使用的定义,在这种情况下,定义intrin.h(取自 VS2010 Ultimate SP1):

__MACHINEI(long _InterlockedExchange(long volatile *, long)) 
__MACHINEIA64(__int64 _InterlockedExchange64(__int64 volatile *, __int64))

正如我们所看到的,它们确实volatile是必需的指针。

最后要注意的是,您的所有链接都是 VS 2005 文档(谷歌默认链接到旧的内在函数),因此请确保使用页面顶部的下拉菜单切换到最新版本。

于 2012-06-06T12:29:16.197 回答
0

这些函数并不需要指向 volatile 的指针,而是允许。也就是说,如果参数被声明为 long* 而不是 long volatile* ,那么传递 volatile 变量的地址会出现此错误:

cannot convert argument 1 from 'volatile LONGLONG *' to 'LONGLONG *'

可以通过以下简单代码看出这一点:

LONGLONG a;
volatile LONGLONG b;

void DoSomething(LONGLONG* p) {}

int main() {
  DoSomething(&a);
  DoSomething(&c); // Error!
  return 0;
}

在 C/C++ 中有一个悠久的传统,即误用 volatile 作为一种指示变量可能被其他线程修改的方式。这是被误导的,因为 volatile 实际上并没有为多线程提供有意义的有用语义,但是当 C++ 不承认多线程开发人员绝望时。使用 volatile 的问题在于它不会阻止编译器或 CPU 重新排序,因此在多线程代码中 99% 的情况下它都是错误的。

如果没有 C++11,安全的做法是只使用 Interlocked* 函数引用这些线程共享变量。如果你这样做,那么 volatile 是不必要的。或者,像理智的人一样使用锁。

但是,由于许多开发人员使用 atomic 标记他们的线程共享变量,因此 Interlocked* 函数必须接受这些变量。这就是为什么它们都采用指向易失性指针的类型。

于 2015-07-14T16:24:14.440 回答