2009-08-18 14 views
1

構造の一部のメンバーに同期を提供する必要があります。
私はプロセッサからの書き込み変数へのアクセスを同期する

obj.Value1 = 5; // Processor B 

はにすぐに見えるようにすることを望ん構造は、この

struct SharedStruct { 
    int Value1; 
    int Value2; 
} 

のようなものであると私はグローバル変数

SharedStruct obj; 

を持っている場合他のプロセッサーなので、値をテストすると

if(obj.Value1 == 5) { DoSmth(); } // Processor A 
else DoSmthElse(); 

キャッシュから古い値ではなく新しい値を取得します。
値を書き込んだり読んだりすると、の揮発性のを使用すれば十分です。しかし、私は揮発性がこのような種類の問題を解決することはできないと読んでいます。
メンバーは2/4/8バイト境界で正しくアライメントされていることが保証されています。この場合、書き込みはアトミックでなければなりませんが、キャッシュがどのようにこれに干渉するかはわかりません。
メモリ障壁(mfence、sfenceなど)を使用すれば十分でしょうか?または、いくつかのインターロック操作が必要ですか?
それとも

lock mov addr, REGISTER 

のようなもの?
たぶん私は少しを明確にすべき:(

編集
最も簡単には明らかにいくつかのロック機構になりますが、速度が重要であり、ロックを余裕はありません。値が(一度だけ設定されているフラグのように振る舞います)。他のすべてのスレッドはそれを読んでする必要があります。私はそれがロックを使用せずに、この新しい値の読み取りを強制する方法であってもよいことだと思う理由です。事前に

ありがとう!

答えて

3

他のすべての答えは、あなたが更新をアトミックになりたいことは事実であるなど、ミューテックスを使用して共有変数の更新の複雑さについての手の波に思えます。 そして、それを保証するためにさまざまなOSプリミティブを使用することができます。それは良いプログラミングスタイルである です。

しかし、現代のほとんどのプロセッサ(確かにx86)では、小さく整列したスカラー値の書き込みはアトミックであり、キャッシュの一貫性のためにすぐに他のプロセッサに見えます。 この特殊なケースでは、すべての同期迷惑メールは必要ありません。ハードウェアは アトミック操作を行います。確かに、これは4バイトの値で安全です(例:32ビットのCコンパイラでは "int")。

だから、あなただけのつまらない値と値1を初期化することができ(例えば0)あなたは並列スレッドを起動し、単にそこに他の値を書き込む前に。質問が固定値(例えば、value1 == 5の場合)でループを終了する場合、これは完全に安全です。

の最初の値をキャプチャすることをお勧めする場合、これは機能しません。しかし、スレッドの並列セットを持っていて、以外の値が書き込まれていない場合は、これも問題ありません。

+0

答えをありがとう。このような何か私は聞くことを望んでいた:) –

7

ありませんあなたのデータが複数のスレッドからアクセスされており、それがその更新が他のスレッドからすぐに見えるようにする必要がある場合は、共有構造体をmutexまたはreaders/writersロックなどの類似のメカニズムで保護する必要があります。

コードを同期するときにパフォーマンスが問題になることはありますが、それは正確性に欠点があります。一般的に言えば、まず正しいことを目指してからコードをプロファイリングします。まだ正確さを捨てていないときのパフォーマンスについて心配するのは時期尚早の最適化です。

2

私は正解を目指すための第2の答えを最初に出します。はい、あなたはここで記憶障壁を使うことができますが、あなたが望むことはしません。

あなたは言ったすぐに。しかし、この更新プログラムがすぐに実行できる方法は、if()句が実行された後にフラグが設定され、その後にDoSmthElse()が実行される可能性があります。これは競合状態と呼ばれます...

何かを同期したいと思われますが、それはではなく、です。

+0

モラル:スレッドは特殊相対性理論での参照のフレームによく似ています:1つでは「即時」は別のものでは「即時」であることが保証されていません;-) –

0

他のスレッドでは、「すぐに」目に見える変化をしなければならないフィールドが揮発性の作りが、スレッドAがスレッドBの後に発生しないアップデートを実行した瞬間は、値ではなく、スレッドBが実行される前にテストするという保証はありませんif/elseステートメントの本体。

あなたが本当にやりたいことのif/else文アトミックことを確認し、それがロック、または状況のこの種の耐性があるアルゴリズムのいずれかが必要になりますように聞こえます。

+0

文は幾分原子的です...私によって作られたスピンロック(私はCRITICAL_SECTIONのように多くのメモリを使用する余裕がありません。これはUniのためにやっているメモリアロケータの一部です)は、if/else文を含むコードの領域を保護します。しかし、私がvolatileを使って値を読み取ったときに、キャッシュから新しい値か何かが得られるかどうかはわかりません。 –

+1

ロックを使用せずにデータに同時にアクセスしようとすると失敗するでしょう。うまくいかないだろう。まったく。 時間の始めから書かれてきた世界全体の機能的な実装はすべてクリティカルセクションを使用しています。これには理由があります。 – peterb

+0

volatileはメモリ同期の問題を解決しません。問題の揮発性の問題は、同期に完全に直交しています(JavaおよびC#を除く)。 –

2

明示的にアトミックな命令を使用してください。私は、ほとんどのコンパイラがこれらを組み込み関数として提供していると信じています。比較と交換は別の良いものです。

ロックレスアルゴリズムを作成する場合は、条件が期待どおりになったときに変更が有効になるように書き込む必要があります。例えば

、あなたが実際に更新を行う際にポインタがまだ同じ場所を指している場合、それだけ挿入されるように、比較/交換のものを使用し、リンクリストのオブジェクトを挿入する場合。

リファレンスカウントを減らしてカウント0でメモリを解放する場合は、何らかの理由で使用できないように事前に解放し、カウントがまだ0であることを確認してから、実際に解放します。またはそのようなもの。

ロックを使用すると、操作をロック解除するのが一般に簡単です。ロックフリーアルゴリズムは本当に難しいです権利を得るために。ここ

関連する問題