2

非常に単純なアプローチ。2 つのスレッド。

volatile __int32 p=0;

1本糸(A)のみ使用

while(1){
    ExecuteAVeryCPUIntesiveThing();
    InterlockedExchange(&p, 0);
}

もう一方のスレッド (B) は

while(1){
    if(0==InterlockedCompareExchange(&p,0,0))
        InterlockedExchange(&p, 1);
}

ストレス下のシステムでこれをログに記録しようとすると。(多くのメモリスワップ、io、ソケット、CPU スパイク..) A からの値は B に伝播されません。

A では、p の値は 0 のように見えます。しかし、B の観点から見ると、p は 1 に固定されています。私の世界では、A が値を 0 に設定すると、B は値を検出して 0 に設定する必要があります。実際のハードウェアでは、これはそのように機能します。 esxiで実行しているときはそうではありません。

これは、実際のハードウェアと一部の仮想システムでは正常に機能するようですが、vmware では機能しないようです。

私はマインドスリップをしましたか...?

OS ゲスト: win2008 サーバー

Microsoft (R) C/C++ Optimizing Compiler バージョン 15.00.30729.01 for x64 でコンパイルされたコード

ホスト: esxi 4.1

アップデート:

コメントへの応答: はい、0 と 1 の間でバウンスしますが、書かれているように、スレッド B はバウンスしません。これは、p からの値が B の視点で決して/またはまったく変化しないためです。10-20 回バウンスしてから停止します。

A ( ExecuteAVeryCPUIntesiveThing();) のコード ブロックを非常に正確なタイミングでのみ実行したいと考えています。

実稼働コードは、より多くのスレッドとイベント、ミューテックスとロックでいっぱいですが、事実は残ります。ゲスト OS で多くの cpu、mm、io を生成すると、上記のコードを削除して使用するだけで再現できます。

4

1 に答える 1

2

このコードは、発生するのを待っているスレッド競合です。仮想マシンに 1 つのプロセッサしか割り当てていないため、VMWare から取得した可能性があります。

コードに欠けているpのは、スレッド B が変化の値を確認したことを保証するインターロックです。したがって、スレッド A が CPU コアを取得してしばらく実行し続け、スレッド B がブロックされ、クォンタムが実行されるのを待っている場合、スレッド A はp複数回 0 に設定できます。pスレッド B は、1 に戻る機会がなかったので、それを認識しません。

ロックの設計を再考する必要があります。問題は VMWare だけに限定されているわけではありません。通常のマシンでも問題が発生する可能性がありますが、その可能性ははるかに低くなります。月に 1 回、ギブ オア テイクで問題が発生し、デバッグできません。それ以外の場合、これは従来のプロデューサー/コンシューマー シナリオであり、スレッド セーフなキューで対処します。

于 2012-04-30T13:26:20.453 に答える