<目次>
(1) C#のlockとは?意味や使い方とサンプルプログラムをご紹介
(1-1) 概要
(1-2) 構文
(1-3) サンプルプログラム
(1-4) lockステートメントを使わないと・・
(1) C#のlockとは?意味や使い方とサンプルプログラムをご紹介
(1-1) 構文
lockステートメントはオブジェクトに対する相互排他(mutual exclusion)を行います。「相互排他」は、複数のプロセスで共有する資源で競合(同時アクセス)が発生した場合に、あるプロセスにて資源をロックして他プロセスが使用できないように排他する事で、データの整合性を保つ仕組みの事をいいます。
(1-2) 構文
lockステートメントで指定したリソース(オブジェクト)に対して相互排他ロックを取得し、ブロック内({ }内)の処理を実行し、処理完了後にロックを解放します。
(構文)
lock ([ロック対象のオブジェクト]) { //# ロック取得後の処理 }
(1-3) サンプルプログラム
●main文(スレッド生成・実行)
スレッド1(thr1)とスレッド2(thr2)を生成・処理実行するmain文です。LockCalc型の「lc」はロック対象のオブジェクト(1度に1スレッドのみロックを許可する)対象です。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace TestProject { class LockStatementTest { static void Main(string[] args) { //# ロック対象のオブジェクト LockCalc lc = new LockCalc(); //# 各スレッドのインスタンス生成 LockTask task1 = new LockTask(lc, 2); LockTask task2 = new LockTask(lc, 3); Thread thr1 = new Thread(new ThreadStart(task1.runCalc)); Thread thr2 = new Thread(new ThreadStart(task2.runCalc)); thr1.Start(); thr2.Start(); } } }
●クラス①:各スレッドの中で実行する処理のオブジェクト
各スレッドにて、累乗計算を起動するクラスです(スレッド処理のクラス)。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TestProject { class LockTask { //# フィールド private LockCalc lc; private int calcTarget; //# コンストラクタ public LockTask(LockCalc lc, int calcTarget) { this.lc = lc; this.calcTarget = calcTarget; } //# 計算メソッドの呼び出し public void runCalc() { //# ■オブジェクトをロック lock (lc) { lc.calculate(calcTarget); } } } }
●クラス②:同期対象のオブジェクト
ロック対象の「LockCalc」クラスです(ただの累乗計算)。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; namespace TestProject { class LockCalc { //# 計算メソッドの呼び出し public void calculate(int num) { for (int i = 1; i <= 5; i++) { Console.WriteLine("{0} の {1} 乗 = {2}", num, i, (int)Math.Pow(num, i)); Thread.Sleep(100); } } } }
(1-4) lockステートメントを使わないと・・
次に上記のサンプルで「lock」ステートメントを指定せずに非同期処理にした例②をご紹介します。この例では「LockCalc」をlockしていないため、1つ目のスレッド(thr1)と2つ目のスレッド(thr2)の計算が交互に入り混じって出力されてしまっています。
//# 計算メソッドの呼び出し public void runCalc() { lc.calculate(calcTarget); }
//# 計算メソッドの呼び出し public void runCalc() { lock (lc) { lc.calculate(calcTarget); } }
(図141)実行結果