排他制御の方法の一つとして、C#にはMutexと呼ばれる機能が用意されています。
何れか一つのスレッドがMutexによるロックを取得することができます。
他のスレッドによりロックが取得されている場合の処理を別途記述すれば、この機能を使用して排他制御が可能となります。
以下、サンプルコードです。
【サンプルコード】
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 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MutexTest { class Program { static void Main(string[] args) { using (Mutex mutex = new Mutex(false)) // 使い終わったらスレッド解放 { const int N = 3; // id0…0.7秒目~1.7秒目に掴む // id1…1.4秒目から待機、1.7~2.7秒目に掴む // id2…2.1秒目から待機、2.6秒目に諦める Parallel.For(0, N, id => // id0~2のスレッドを生成 { Thread.Sleep(id * 700); // ロック取得、成功ならtrue // 第一引数は待ち時間 if (mutex.WaitOne(500, false)) { try { Console.WriteLine("ID" + id + "が掴みました。"); Thread.Sleep(1000); } finally { // Mutex資源解放 // 忘れてCloseすると待機待ち側でAbandonedMutexException // Disposeでは実行されないためusingに頼るのは不可 mutex.ReleaseMutex(); Console.WriteLine("ID" + id + "が解放しました。"); } } else { Console.WriteLine("ID" + id + "は掴めませんでした。"); } }); } Console.ReadKey(); } } } |
【実行結果】
1 2 3 4 5 |
ID0が掴みました。 ID0が解放しました。 ID1が掴みました。 ID2は掴めませんでした。 ID1が解放しました。 |
また、Mutexには、名前を付けることができます。
名前を付けることで、プロセス間でも排他制御が可能となります。
ただし、意図せずMutex名が被ると意図しないロックがかかってしまうため、扱いには注意が必要です。
【サンプルコード】
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 |
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace MutexTest2 { class Program { static void Main(string[] args) { // 名前付きMutexだとプロセス間で共有できる //using (Mutex mutex = new Mutex(false)) using (Mutex mutex = new Mutex(false,"hoge")) { // プロセス名取得(表示用) System.Diagnostics.Process p = System.Diagnostics.Process.GetCurrentProcess(); Console.WriteLine(DateTime.Now); Console.WriteLine(p.Id + "が掴もうとしています。"); if (mutex.WaitOne(5000, false)) { try { Console.WriteLine(DateTime.Now); Console.WriteLine(p.Id + "が掴みました。"); Thread.Sleep(10000); } finally { mutex.ReleaseMutex(); Console.WriteLine(DateTime.Now); Console.WriteLine(p.Id + "が解放しました。"); } } else { Console.WriteLine(DateTime.Now); Console.WriteLine(p.Id + "は掴めませんでした。"); } } Console.ReadKey(); } } } |
【実行結果】
※exeファイルを3回起動した結果。
1つ目のプロセス…掴んで解放
2つ目のプロセス…解放を待って掴んで解放
3つ目のプロセス…解放を待って掴めず諦める
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
2020/04/18 7:01:44 10420が掴もうとしています。 2020/04/18 7:01:44 10420が掴みました。 2020/04/18 7:01:54 10420が解放しました。 2020/04/18 7:01:50 2416が掴もうとしています。 2020/04/18 7:01:54 2416が掴みました。 2020/04/18 7:02:04 2416が解放しました。 2020/04/18 7:01:56 7524が掴もうとしています。 2020/04/18 7:02:01 7524は掴めませんでした。 |
いかがでしたでしょうか?
C#には排他制御のための機能が色々と用意されています。
その内の一つが今回紹介したMutexであり、名前を付けることでプロセス間の排他制御も可能になります。
名前付きMutexは、プロセスをまたいだスレッドの制御だけでなく、同じ画面が複数立ち上がらないようにする、といった使われ方もします。
仕組みが単純なので使用しやすく、排他制御の機能の中では使用頻度は高いと思います。
排他制御の機能は他にも色々と用意されているので、今後も紹介していきたいと思います!
コメント