9

私はしばらく VB.NET で単純なマルチスレッドを行ってきましたが、初めての大規模なマルチスレッド プロジェクトに取り掛かりました。Synclockより良い方法があるとは思わなかったので、私は常にステートメントを使用してすべてを行ってきました。

Classについて学んだばかりですInterlocked- それはすべてこのように見えます:

Private SomeInt as Integer
Private SomeInt_LockObject as New Object

Public Sub IntrementSomeInt
    Synclock SomeInt_LockObject
        SomeInt += 1
    End Synclock
End Sub

次の 1 つのステートメントに置き換えることができます。

Interlocked.Increment(SomeInt)

これにより、すべてのロックが内部で処理され、番号が変更されます。これは、単純な操作に対して独自のロックを作成するよりもはるかに簡単です (長時間実行される操作やより複雑な操作には、明らかに独自のロックが必要です)。

メソッドを使用して同じことを達成できるのに、専用のロックオブジェクトを使用して独自のロックをロールする理由はありInterlockedますか?

4

5 に答える 5

9

あなたは正しいです。Interlockedここでは を使用する必要があり、 よりも高速になりSyncLockます。
しかし、そのInterlockedクラスはあまり知られていません。

ただし、使用する必要があり、役に立たない状況がありSyncLockますInterlocked

于 2010-03-28T21:06:51.533 に答える
5

これは、誰もそのことを知らないからです。言葉を広める!

于 2010-03-28T21:07:08.300 に答える
4

簡単な答えは、 ( VB およびC# で)Monitorロックを使用すると、一度に 1 つのスレッドのみが変数にアクセスできることが保証されるだけでなく (厳密な意味では、一度に 1 つのスレッドのみがロックのロックを取得できるため) です。オブジェクト) ですが、変数の読み取りが最適化されないようにするために必要なメモリ バリアも作成されます。SyncLocklock { }

変数の値を単純に読み取らない場合 (つまり、すべての作業が への呼び出しによって行われるInterlocked場合) は問題ありません。ただし、変数の通常の読み取りを実行できるようにする必要がある場合、状況はより複雑になります。ロックレス読み取り/書き込みは、通常、volatileキーワードを使用して C# で実行されます。これにより、ローカル キャッシュへの読み取りを最適化するのではなく、変数が使用されているすべての場所で変数の値を読み取るようにコンパイラに指示します。残念ながら、VB.NET には同等のものがないため、別のものを使用する必要があります。

この質問に対する受け入れられた回答は、何ができるかについての詳細情報を提供するはずです。SyncLockつまり、VB.NET を使用しない場合に必要なロジックよりも簡単で複雑でないため、ほとんどの人が VB.NET で使用SyncLockます。

于 2010-03-28T21:19:15.357 に答える
2

私はかつて、いわゆる非アトミックおよびアトミック(VBではインターロック)操作に関する非常に優れた説明を読み、それを要約しようとします。

Normal "non-atomic" operations consist of several steps 

->他のスレッドはそれらのstrepsの間に動作できます

"Atomic" operations consist of one only one step 

->アトミ​​ック操作が処理されている間、他のスレッドは作業を実行できません。アトミック操作は常に全体として処理されます

インターロックされたクラスは、そのようなアトミック操作のコレクションであるため、定義上、スレッドセーフです。複数のスレッドが同じ変数に対して読み取りおよび書き込み操作を実行している場合でも、これらの操作は完全にスレッドセーフです。

それでも、これらのスレッドセーフコマンドの組み合わせは、アトミック操作の間に競合状態が発生する可能性があるため、安全ではない可能性があります。

したがって、たとえば2つの変数を比較してから小さい方の変数をインクリメントする場合、それら自体の単一の操作(interlocked.compare、interlocked.increment)であっても、これはスレッドセーフではありません。ここでも、同期ロックを使用する必要があります。

その制限を除いて、インターロックの「隠れた悪い面」はありません。

a =5のレース条件の1つの例:

 Thread1: a+=1
 Thread2: a+=2    
 --> supposed to be 8, but can be only 6 or 7,
 but can also be 6 or 7 depending on which thread wins the race

オプション1:

T1 step 1: read 5
T1 step 2: add 1 = 6
T1 step 3: write 6
T2 step 1: read 6
T2 step 2: add 2 = 8
T2 step 3: write 8
--> is 8 as supposed

またはオプション2:

T1 step 1: read 5
T2 step 1: read 5
T1 step 2: add 1 = 6
T2 step 2: add 2 = 7
T2 step 3: write 7
T1 step 3: write 6
--> is only 6

またはオプション3:

T1 step 1: read 5
T2 step 1: read 5
T1 step 2: add 1 = 6
T2 step 2: add 2 = 7
T1 step 3: write 6
T2 step 3: write 7
--> is only 7

interlocked.incrementを使用:

オプション1:

T1 step 1: read 5, add 1, write 6
T2 step 1: read 6, add 2, write 8

またはオプション2:

T2 step 1: read 5, add 2, write 7
T1 step 1: read 7, add 1, write 8

->すべての場合でa=8と想定される、スレッドセーフなソリューション

ここに投稿されたすべての質問は、この簡単な例を疑わしいコードに適用することで解決できます。

これがこのトピックをグーグルで検索する他の人々に役立つことを願っています。ジャニス

于 2012-11-07T15:36:31.227 に答える
1

InterlockedInteger、Long、Boolean などの単純な操作に限定されます。

たとえば、アイテムを共有 List(of T) に追加する場合でも、SynClock.

于 2010-03-28T21:20:56.217 に答える