0

タイマーイベントハンドラーでインクリメントされ、メインおよび他のワーカースレッド、つまり1つのライタースレッドと複数のリーダースレッドによって読み取られる整数をインクリメントしたいと考えています。それはスレッドセーフになりますか?

アプリケーションに 5 秒ごとに実行されるタイマーがあります

MyClock = new System.Threading.Timer( new TimerCallback(this.Ticker), null, Timeout.Infinite, Timeout.Infinite );

この MyClock.Change( 5000, 5000 ); のようにオンにします。

この tickerCounter++ のように、ティッカー ハンドラーで整数をインクリメントするとします。

その後、同じアプリケーションのメイン スレッドまたはワーカー スレッドから読み取り専用アクセスを行うことはできますか? スレッドセーフになりますか?読者が部分的な値を読み取る可能性はありますか? またはスレッド例外を引き起こしていますか?

4

3 に答える 3

3

まず、Eric Lippert のブログ記事を読んでください: What is this thing you call "thread-safe"? スレッド セーフについての考え方や、今後同様の質問をする方法が変わります。

読み取りはアトミックになります。更新の「半分」は表示されませんが、必ずしも最新の値が表示されるとは限りません。(つまり、次のインクリメントでは、もちろん、インクリメントする「古い」(低い) 値が表示される可能性があります。)

さらに、インクリメント自体は本質的に安全ではありません。複数のスレッドが同時にインクリメントしている場合、それらはすべて同じ値を読み取り、ローカルでインクリメントしてから新しい値を書き込む可能性があるため、結果はインクリメント 1 になる可能性があります。 10 個のスレッドが増加していたとしても。

Interlocked.Incrementインクリメントの実行にはを使用することを検討する必要があります。変数もvolatile にすると、読みたいだけのときに直接読み込めば安全だと思います。

于 2012-05-11T18:48:50.980 に答える
2

おそらくInterlocked.Increment(ref Int32)、インクリメントを行うために使用できますか?それはアトミック操作としてそれを行います。

于 2012-05-11T18:47:42.453 に答える
1

このように増えていきます

tickerCounter++;

複数のスレッドでは、ロックなしではスレッドセーフではありません。このInterlockedクラスを使用して、ロックフリーでスレッドセーフなインクリメントを実行できます。

単一のスレッドのみが値を変更し、多くのスレッドが値を読み取っている場合、tickerCounter++スレッドが部分読み取りを受けることはないという意味でスレッドセーフです。もちろん競合状態はInterlockedありますが、 を使用しても競合が発生します。

于 2012-05-11T18:48:47.610 に答える