none
【C#】MutexのWaitOne()について RRS feed

  • 質問

  • アプリケーションの多重起動防止のために、下記のようにMutexを使っています。

    -----------------------------------------------------------------

    namespace WpfApplication1
    {
        public partial class App : Application
        {
            private static System.Threading.Mutex mutex;

            private void Application_Startup(object sender, StartupEventArgs e)
            {
                /* Mutexを生成 */
                mutex = new System.Threading.Mutex(false, "App_Mutex");

                /* 二重起動をチェック */
                if ( mutex.WaitOne(0, false) != true)
                {
                    /* 二重起動の場合はエラーを表示して終了 */
                    MessageBox.Show("すでに起動されています");

                    /* Mutexを破棄 */
                    mutex.Close();
                    mutex = null;

                    /* 起動を中止してプログラムを終了 */
                    this.Shutdown();
                }

          以下処理

            }

            private void Application_Exit(object sender, ExitEventArgs e)
            {
                if (mutex != null)
                {
                    /* Mutexを解放 */
                    mutex.ReleaseMutex();

                    /* Mutexを破棄 */
                    mutex.Close();
                }
            }
        }
    }

    -----------------------------------------------------------------

    Debugモードでビルドして、「デバッグ開始(F5)」で実行すると、問題は無いのですが、

    同じDebugモードのまま、「デバッグなしで開始(Ctrl+F5)」で実行すると、

    mutex.WaitOne(0, false)の戻り値がfalseとなり、多重起動していると判断されます。

    また、Mutex生成前に1秒待つ(System.Threading.Thread.Sleep(1000))と

    両方の実行で、mutex.WaitOne(0, false)の戻り値がtrueとなり正常に判定されます。

      ※二つ目のExeを実行するとちゃんと多重起動防止が働きます。

    この現象は何故起きるのでしょうか。

    ご存知の方いらっしゃいましたら、ご教授ください。

    • 移動 星 睦美 2015年7月21日 0:58 Windows クライアント開発 から
    2015年7月16日 19:26

回答

  • その目的であれば、3引数のMutexコンストラクタを使えばいいのでは。

     bool new_mutex;
     mutex = new System.Threading.Mutex(false, "App_Mutex", out new_mutex);
     if( !new_mutex ) {  
      //あとから起動された側のプロセス。
      this.Shudown();
     }
    



    jzkey

    2015年7月17日 7:34

すべての返信

  • Mutexの使い方が根本的に間違っています。

    new Mutex(false, "App_Mutex"); はマシン内で1度しか実行できません。既にMutexが作成済みの場合は後から実行した側が失敗します。後から実行する側はMutex.OpenExisting()を使います。(この時点で先に起動しているアプリケーションが存在することが分かってしまうわけですが…)

    # タイトルに 【C#】 などと付けるぐらいなら初めからC#フォーラムを選択すべきです。モデレーターさん移動をお願いします。
    • 編集済み 佐祐理 2015年7月17日 0:15
    2015年7月16日 22:44
  • // 質問の回答ではありません。

    new Mutex(false, "App_Mutex"); はマシン内で1度しか実行できません。既にMutexが作成済みの場合は後から実行した側が失敗します。

    いいえ、そんなことはありません。同じ名前のミューテックスを複数newできます。存在していなければ作られますし、存在していれば既存のを開きます(アクセス制御による権限違いで失敗とかのケースはありますが)。

    これはWindows APIのCreateMutex関数でも同じです。

    本題とは関係ないですが、Mutex.WaitOneを呼び出す際は、AbandonedMutexExceptionを処理しておいた方が良いです。前のプロセスが強制終了してReleaseMutexが呼ばれていなかった際に、後続のプロセスで発生し得ます。

    2015年7月17日 0:17
  • んー普通のWindowsアプリ間で、権限に問題がない使い方の場合はnewでも行けると思いますよ。

    2015年7月17日 0:17
  • 失礼しました。作りますとあるからできないと思っていました。
    2015年7月17日 1:12
  • その目的であれば、3引数のMutexコンストラクタを使えばいいのでは。

     bool new_mutex;
     mutex = new System.Threading.Mutex(false, "App_Mutex", out new_mutex);
     if( !new_mutex ) {  
      //あとから起動された側のプロセス。
      this.Shudown();
     }
    



    jzkey

    2015年7月17日 7:34
  • 「デバッグ開始(F5)」で実行した場合、ホスティングプロセス 及び devenv.exeが 動作することで二重起動と判定されるようです。以下のURLに紹介記事がありましたので、よろしければ参照にしてください。

    http://www.bnote.net/vb/process_mutex.shtml


    • 編集済み HIDE0707 2015年7月18日 5:43
    2015年7月18日 5:14
  • 返信が遅れました。

    確かに多重起動防止なので、WaitOneする必要は無いですね。

    教えていただいた方法で、うまく行きました。

    ありがとうございます。

    2015年7月21日 19:19