スレッドセーフなカウンタ(Interlockedクラス)
プログラミングC# p515
排他制御の典型的なやつ。入金と出金。
残高が100万円ある口座に対して、20万円の引き出しと30万円の預け入れを同時にやってみる。
using System; using System.Threading; class ThreadTest { private static int zandaka = 1000000; static void Main(string[] args) { ThreadStart ts1 = new ThreadStart(delegate(){ int currentZandaka = zandaka; // 残高を使ったチェックなどの処理 Thread.Sleep(100); // 残高を減額(引き出し) zandaka = currentZandaka - 200000; //Interlocked.Add(ref zandaka, -200000); }); ThreadStart ts2 = new ThreadStart(delegate(){ int currentZandaka = zandaka; // 残高を使ったチェックなどの処理 Thread.Sleep(100); // 残高を増額(預け入れ) zandaka = currentZandaka + 300000; //Interlocked.Add(ref zandaka, 300000); }); Thread t1 = new Thread(ts1); Thread t2 = new Thread(ts2); t1.Start(); t2.Start(); t1.Join(); t2.Join(); Console.WriteLine("zandaka = {0}", zandaka); } }
結果はこう。(実行環境によっては違う場合もあり)
zandaka = 1300000
100万 - 20万 + 30万 = 130万円(?) というおいしい結果に(汗
というわけでコメントを付けはずしして、Interlockオブジェクトを使うようにする。
using System; using System.Threading; class ThreadTest { private static int zandaka = 1000000; static void Main(string[] args) { ThreadStart ts1 = new ThreadStart(delegate(){ int currentZandaka = zandaka; // 残高を使ったチェックなどの処理 Thread.Sleep(100); // 残高を減額(引き出し) //zandaka = currentZandaka - 200000; Interlocked.Add(ref zandaka, -200000); }); ThreadStart ts2 = new ThreadStart(delegate(){ int currentZandaka = zandaka; // 残高を使ったチェックなどの処理 Thread.Sleep(100); // 残高を増額(預け入れ) //zandaka = currentZandaka + 300000; Interlocked.Add(ref zandaka, 300000); }); Thread t1 = new Thread(ts1); Thread t2 = new Thread(ts2); t1.Start(); t2.Start(); t1.Join(); t2.Join(); Console.WriteLine("zandaka = {0}", zandaka); } }
結果はこう。
zandaka = 1100000
正しく計算されました。