Skip to content

Instantly share code, notes, and snippets.

@in-async
Last active August 14, 2020 03:44
Show Gist options
  • Save in-async/fc26db116ba32f617e15931680bda383 to your computer and use it in GitHub Desktop.
Save in-async/fc26db116ba32f617e15931680bda383 to your computer and use it in GitHub Desktop.
アプリケーション単位の排他制御を行う .NET クラス。
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Threading;
namespace InAsync.Threading {
/// <summary>
/// アプリケーション単位の排他制御を行うクラス。
/// </summary>
public static class ApplicationLock {
/// <summary>
/// アプリケーション毎に一意の <see cref="Guid"/>。
/// </summary>
/// <remarks>
/// アプリケーションの <see cref="Guid"/> の取得については下記を参考にした。
/// https://stackoverflow.com/questions/502303/how-do-i-programmatically-get-the-guid-of-an-application-in-net2-0/11486085#11486085
/// </remarks>
private static readonly Guid _appGuid = Marshal.GetTypeLibGuidForAssembly(Assembly.GetExecutingAssembly());
/// <summary>
/// 排他制御のキーとなるシステムミューテックス名。
/// </summary>
/// <remarks>
/// Global プリフィクスについては下記を参照。
/// https://dobon.net/vb/dotnet/process/checkprevinstance.html#section2
/// </remarks>
private static readonly string _mutexName = $@"Global\{{{_appGuid}}}";
/// <summary>
/// プロセス間の排他制御を行う為の <see cref="Mutex"/> オブジェクト。
/// </summary>
/// <remarks>
/// アプリケーション終了時にファイナライザーによって自動的に <c>Dispose</c> されるので、明示的に <c>Close</c> しなくても良い。
/// </remarks>
private static Mutex _mutex;
/// <summary>
/// クリティカルセクションへの入場権の取得を試みます。
/// </summary>
/// <returns>クリティカルセクションへの入場権を取得できれば <c>true</c>、それ以外なら <c>false</c>。</returns>
public static bool TryEnter() {
// 既に排他制御されているか否かは、システムミューテックスを新規作成できるか否かで判定する。
// システムミューテックスを新規に作成できれば、_mutexName に対する排他制御が行われていないと判定できる。
// システムミューテックスは全てのハンドルが閉じられた時点で自動的に破棄される(https://msdn.microsoft.com/ja-jp/library/cc429275.aspx)。
// _mutex はシステムミューテックスのハンドルを保持している為、アプリケーション終了時に Close 又は Dispose する必要がある。
// 一方で、Mutex (厳密には SafeHandle) はファイナライザーを実装している為、アプリケーション終了時に自動的に Dispose される。
_mutex = new Mutex(false, _mutexName, out var createdNew);
if (createdNew == false) {
_mutex.Close();
_mutex = null;
}
return createdNew;
}
}
}
@in-async
Copy link
Author

in-async commented Aug 16, 2018

Process を使った多重起動禁止コードを一行変えるだけで、 Mutex による多重起動禁止が可能になります!

Before

static void Main() {
    // 多重起動チェック。
    if (Process.GetProcessesByName(Process.GetCurrentProcess().ProcessName).Length > 1) {
        Console.WriteLine("プログラムは既に起動しています。多重起動は許可されません。");
        return;
    }

    // メイン処理
    // ...
}

After

static void Main() {
    // 多重起動チェック。
    if (ApplicationLock.TryEnter() == false) {
        Console.WriteLine("プログラムは既に起動しています。多重起動は許可されません。");
        return;
    }

    // メイン処理
    // ...
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment