1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
using System; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp1 { static class Program { [STAThread] static void Main() { Parallel.For(0, 3, x => { MessageBox.Show(x.ToString()); // 0, 1, 2 が同時に表示される。3つのスレッドとなっている(順番も不定) }); // 終了インデックスは-1となる Parallel.For(2, 5, x => { MessageBox.Show(x.ToString()); // 2, 3, 4 が同時に表示される。3つのスレッドとなっている(順番も不定) }); // 各スレッドが同時に処理を行ってはいけない部分(排他セクション)に入る前に // 同期オブジェクト(lockObject)に対し、1つのスレッドから排他ロックを行い、 // 処理が終わったら排他ロックを解除する。 // MonitorクラスのEnter()とExit()の場合。 // 以下のようにするとMessageBoxは一つずつの表示となる。 var lockObject = new object(); Parallel.For(0, 3, x => { bool lockTaken = false; System.Threading.Monitor.Enter(lockObject, ref lockTaken); MessageBox.Show(x.ToString()); if (lockTaken) System.Threading.Monitor.Exit(lockObject); // Enter()せずにExit()とすると、非同期ブロックからの呼び出しでエラーとなる。 }); // lock文が標準である。内部的にはEnter(),Exit()と同じ。 var lockObject = new object(); Parallel.For(0, 3, x => { lock(lockObject) { MessageBox.Show(x.ToString()); } }); // lock文は以下のように展開されるらしい。 object syncObject = new object(); bool taken = false; try { System.Threading.Monitor.Enter(syncObject, ref taken); } finally { if (taken) System.Threading.Monitor.Exit(syncObject); } } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
using System; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApp1 { static class Program { [STAThread] static void Main() { // 共有オブジェクトがインスタンスのスコープなので、 // 以下の場合A:0, B:0は同時に表示される。 var t1 = Task.Run(() => { new TestClass("A"); }); new TestClass("B"); // 共有オブジェクトのスコープを呼び出し元にすれば、 // AA, BBは同時に表示されない。 object syncObject = new object(); var t2 = Task.Run(() => { new TestClass2("AA", syncObject); }); new TestClass2("BB", syncObject); // この実験の場合のように書くとBB:1が表示された時点で本体が終了してしまうため、 // 4回すべて表示されないことも多い。 } } public class TestClass { object syncObject = new object(); public TestClass(string n) { Parallel.For(0, 2, x => { lock (syncObject) { MessageBox.Show(n + ":" + x.ToString()); } }); } } public class TestClass2 { public TestClass2(string n, object syncObject) { Parallel.For(0, 2, x => { lock (syncObject) { MessageBox.Show(n + ":" + x.ToString()); } }); } } } |