しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

.NET Framework における GC と Mutex の関係

Mutex を使ってアプリケーションの多重起動をブロックする場合、検索して見つかるのは以下のような実装。

Mutex mutex = new Mutex(false, "hoge");
if (!mutex.WaitOne(false, 0))
{
    // 既に起動されている
    return;
}
Application.Run(new Form1());

Mutex をローカル変数で作成しているので、ガベージコレクタに回収されてしまう可能性があるわけです。そこで GC.KeepAlive を呼び出して回収対象からはずしてやろうと思ったのですが、どの時点で呼び出すのかちょっと迷いました。

普通に考えれば、WaitOne で所有権が獲得出来てから呼べばいいと思っていたのですが、検索していると Application.Run でメッセージループを起動した後に呼び出してるものもありました。落ち着いて考えれば、Application.Run を呼び出した時点で実行が止まってしまうわけなので、その後に呼び出してもあまり意味はないと思うのですが。

いろいろ考えた結果、以下のようなコードに落ち着きました。

using (Mutex mutex = new Mutex(false, "hoge"))
{
    if (!mutex.WaitOne(false, 0))
    {
        // 既に起動されている
        return;
    }
    // using を使用しているので不要
    //GC.KeepAlive(mutex);
    Application.Run(new Form1());
}

ガベージコレクタが関係すると、タイミングしだいで動いたり動かなかったりするので結構厄介でした。

追記

using が展開されて Application.Run(new Form1()) の後に mutex.Dispose が呼ばれるので、GC.KeepAlive は不要でした。NyaRuRu さんに感謝です。