using System;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
internal static class Program
{
[STAThread]
static void Main()
{
string mutexName = System.Diagnostics.Process.GetCurrentProcess().MainModule.ModuleName; // 固有の文字列にする
// Mutexコンストラクタ引数
// 第一引数
// インスタンスを作成したスレッドに所有権を与えるかどうか (True=与える, False=与えない)
// Trueの場合はインスタンス生成時にスレッドが所有権を取得する。
// WaitOne()も同じく所有権を取得するが、
// 取得できるまで現在のスレッドが待機状態となる。
// コンストラクタ(第一引数)で所有権を取得する場合は待機しない。
// 第二引数
// インスタンスの名前
// 名前付きにするとOS全体で排他制御できる。
// 名前無しにするとローカルの排他制御のみ。
// 第三引数
// Mutexを作成したかどうかのフラグ。(初期所有権とは関係ない)
// すでに同名のMutexが存在している場合は作成できないのでFalseとなる。
// ReleaseMutex()は所有権を解放状態=シグナル状態(signaled)になる。
// ReleaseMutex()はWaitOne()したスレッドからしか呼べない。
// 所有権を解放せずに終了した場合は、放棄状態(abandoned)となり、
// 他のスレッドからのWaitOne()するとExceptionとなる。
// ReleaseMutex()は呼び出しと同じ回数必要
if (false)
{
var m = new System.Threading.Mutex(false, mutexName);
// 初期所有権:取得しない。
bool f = m.WaitOne(0, false);
// WaitOne()で所有権の取得を試みる。
MessageBox.Show(f.ToString());
// 最初に起動したときはTrue
// MessageBoxが表示されているとき、もう1つ起動するとFalse。
}
if (false)
{
var m = new System.Threading.Mutex(false);
// 初期所有権:取得しない。
// 名前付きではない
bool f = m.WaitOne(0, false);
// WaitOne()で所有権の取得を試みる。
MessageBox.Show(f.ToString());
// 最初に起動したときはTrue
// MessageBoxが表示されているとき、もう1つ起動してもTrue
}
// --------------------------------------------------------
// 第三引数の実験
if (false)
{
var m = new System.Threading.Mutex(true, mutexName, out bool initialOwnership);
// 初期所有権:取得。
MessageBox.Show(initialOwnership.ToString());
// 最初に起動したときはTrue
// MessageBoxが表示されているとき、もう1つ起動するとFalse。
}
if (false)
{
var m = new System.Threading.Mutex(false, mutexName, out bool initialOwnership);
// 初期所有権:取得しない。
MessageBox.Show(initialOwnership.ToString());
// 最初に起動したときはTrueとなる。
// MessageBoxが表示されているとき、もう1つ起動するとFalse。
// ## 注意 ##
// 最初のMessageBoxでは、初期所有権を取得していないがTrueとなるので、
// ここは作成されたかどうか判断している模様。
}
// --------------------------------------------------------
// Close,Dispose()後に別スレッドから同名のMutexを作成(コンストラクタ)。
if (false)
{
var m1 = new System.Threading.Mutex(true, mutexName,out bool f1);
MessageBox.Show(f1.ToString()); // true
Task.Run(() => {
var m2 = new System.Threading.Mutex(true, mutexName, out bool f2);
MessageBox.Show(f2.ToString()); // false
// Close()していないので作成できない
});
MessageBox.Show(""); // これがないとTaskを実行したまま終了してしまう
}
if (false)
{
var m1 = new System.Threading.Mutex(true, mutexName, out bool f1);
MessageBox.Show(f1.ToString()); // true
m1.Close(); // ここがDispose()でも同じ
Task.Run(() => {
var m2 = new System.Threading.Mutex(true, mutexName, out bool f2);
MessageBox.Show(f2.ToString()); // true
// Close()しているので作成できる。
});
MessageBox.Show(""); // これがないとTaskを実行したまま終了してしまう
}
// --------------------------------------------------------
// 作成したMutexを別スレッドでもう一度つかむ。
if (false)
{
var m = new System.Threading.Mutex(true, mutexName, out bool f);
MessageBox.Show(f.ToString()); // true
// この部分で、
// 何も記載しないと、待機してしまいTask内のMessageBoxは表示されない
// m.ReleaseMutex();
// だけだと下記Taskの中で再度取得(true)できる。
// m.ReleaseMutex();
// m.Close();
// と2つ呼んだ場合、
// m.Close();
// と1つ呼んだ場合
// のどちらも取得できない。(ObjectDisposedException)
Task.Run(() => {
try
{
MessageBox.Show(m.WaitOne().ToString());
}
catch(Exception e)
{
MessageBox.Show(e.ToString());
}
});
MessageBox.Show(""); // これがないとTaskを実行したまま終了してしまう
}
// --------------------------------------------------------
// WaitOne()状態でインスタンス破棄
// AbandonedMutexException
if (false)
{
try
{
var m = new System.Threading.Mutex(false, mutexName);
m.WaitOne();
// ここにClose()などあると発生しない
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
MessageBox.Show("");
// 1つ目を起動しMessageBoxが表示されている状態で、2つ目を起動すると、
// 1つ目のMessageBoxが表示されている間は2つ目のMessageBoxは表示されず、
// 1つ目のMessageBoxを閉じると、2つ目の方がAbandonedMutexExceptionになる。
// 2つ目がWaitOne()している状態で、1つ目がReleaseMutex()せず終了したため。
// WaitOne()のあとにClose()やReleaseMutex()があれば、AbandonedMutexExceptionにはならない
// ## 注意 ##
// m.ReleaseMutex();
// m.Close();
// と2つ呼んだ場合、
// m.Close();
// と1つ呼んだ場合
// どちらも、AbandonedMutexExceptionは発生しない
}
// --------------------------------------------------------
// 別スレッドからReleaseMutex()
// ApplicationException
if (true)
{
var m = new System.Threading.Mutex(true, mutexName);
Task.Run(() => {
try
{
m.ReleaseMutex();
// 別スレッド以外からReleaseMutex()を呼んでいるのでApplicationExceptionが発生
// Close()の場合発生しない
}
catch (Exception e)
{
MessageBox.Show(e.ToString());
}
});
MessageBox.Show(""); // これがないとTaskを実行したまま終了してしまう
}
}
}
}