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()があり、揮発性がないことに注意してください。

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

__int64 _InterlockedExchange64( __int64 * Target, __int64 Value );

次に、InterlockedExchange64()と同様にvolatileを使用するInterlockedExchangePointer()があります。

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の本能は、交換のための揮発性については言及していませんが、CASについても言及していません!だからそれは助けにはなりません。

私の見解では、CASターゲットは揮発性です。これは、実行時に交換が発生するかどうかしかわからないためです。ただし、ターゲットは常に更新されるため(値が変更されない場合でも)、アトミック交換は揮発性であってはなりません。したがって、コンパイラーには不確実性がありません。

InterlockedIncrement()の関数も揮発性ですが、instrincsは揮発性ではありません。CASの本質は、宛先に対して不安定です。

4

2 に答える 2

3

MSDNには、ほとんどのマイナーなドキュメントエラーがたくさんあります(たとえば、__readfsdwordVS 2005ドキュメントでのみカーネルとしてマークされています)。コンパイラが使用する定義、この場合はintrin.h(VS2010 Ultimateから取得)の定義に注意する必要があります。 SP1):

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

ご覧のとおり、これらは実際にvolatile必要なポインターです。

最後に注意しなければならないのは、すべてのリンクはVS 2005ドキュメント(古い組み込み関数の場合はデフォルトでgoogleによってリンクされている)なので、ページ上部のドロップダウンを使用して最新バージョンに切り替えるようにしてください。

于 2012-06-06T12:29:16.197 に答える
0

これらの関数でvolatileへのポインタが必要なわけではなく、許可されているということです。つまり、パラメータがlong volatile*ではなくlong*として宣言されている場合、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*関数を使用してこれらのスレッド共有変数のみを参照することです。これを行う場合、揮発性は不要です。または、正気の人のようにロックを使用します。

ただし、多くの開発者はスレッド共有変数にアトミックなタグを付けるため、Interlocked*関数がそれらの変数を受け入れる必要があります。そしてそれが、それらすべてが揮発性へのポインタのタイプをとる理由です。

于 2015-07-14T16:24:14.440 に答える