Mutex не выпускает - PullRequest
       26

Mutex не выпускает

2 голосов
/ 18 июля 2010

My c # WinForm решение содержит несколько проектов, включая проект Admin, содержащий frmAdmin, и проект User, содержащий frmUser. Третий проект содержит frmTimer с таймером, который периодически запускает frmUser.

Я хочу, чтобы frmTimer не запускал frmUser при открытом frmAdmin.

Я использую именованный мьютекс, чтобы сообщить frmTimer, открыт ли frmAdmin; однако мьютекс, по-видимому, не освобождается после закрытия frmAdmin.

Мьютекс создается в frmAdmin с кодом, подобным следующему:

public partial class frmAdmin : Form
{
    Mutex m;
    protected override void OnShown(EventArgs e)
    {
        base.OnShown(e);
        m = new Mutex(true, "frmAdmin");
    }
    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);
        m.ReleaseMutex();
        MessageBox.Show("Debug 1 -- In the frmAdmin ONCLOSED Event.");  //test code
        Debug.WriteLine("Debug 1 -- In the frmAdmin ONCLOSED Event.");  //test code
  }

    public frmAdmin(string strPassedFromLogin)
    {
        InitializeComponent();
        <<Code snipped>>
             }

    private void frmAdmin_FormClosing(object sender, FormClosingEventArgs e)
    {
        //Start _ Added
        bool mutexSet = true;
        try
        {
            Mutex.OpenExisting("frmAdmin");
            MessageBox.Show("Debug 2 -- In the frmAdmin FORMCLOSING Event.");  //test code
        }
        catch (WaitHandleCannotBeOpenedException)
        {
            mutexSet = false;
        }
        if (mutexSet)
        {
            base.OnClosed(e);
            m.ReleaseMutex();
        }
        //End _ Added

        Application.Exit();
    }

    <<Code snipped>>
}

Изначально у меня не было никакого кода мьютекса в методе frmAdmin_FormClosing (метод содержал только строку Application.Exit ()). Я добавил код мьютекса в попытке освободить мьютекс, но он все еще не освобождается.

Мьютекс используется в frmTimer следующим образом:

    private void tmTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        bool adminIsOpen = true;
        try
        {
            Mutex.OpenExisting("frmAdmin");
            MessageBox.Show("Debug 3 -- Mutex exists: frmAdmin IS open.");  //test code
        }
        catch (WaitHandleCannotBeOpenedException)
        {
            adminIsOpen = false;
            MessageBox.Show("Debug 4 -- Mutex doesn't exists: frmAdmin is NOT open.");  //test code
        }

        if (adminIsOpen == false)
        {
          //frmAdmin is closed; go ahead and open frmUser.
            <<Code snipped>>
        }
    }

Когда я запускаю приложение, окно сообщения с текстом «Отладка 4» появляется каждый раз, когда запускается таймер, пока я не открою frmAdmin (frmAdmin запускается из frmLogin после проверки пароля), с этого момента в окне сообщения с «Отладка 3» Текст появляется каждый раз, когда срабатывает таймер, даже после того, как я выйду из frmAdmin. При выходе из frmAdmin я вижу окно сообщения с текстом «Отладка 2». Я никогда не видел окно сообщения (или сообщение окна вывода) с текстом «Отладка 1».

Похоже, что мьютекс не освобождается после закрытия frmAdmin, и это препятствует запуску frmUser.

Любая помощь приветствуется.

Это дополнительный вопрос к этому вопросу.

UPDATE

Вот мой код после того, как он заработал. Я получил его на работу из-за ответов Ганса Пассанта и Криса Тейлора и Серхио из этой записи.

Теперь мьютекс создается в frmAdmin с кодом, подобным следующему:

    Mutex m;
    protected override void OnShown(EventArgs e)
    {
        base.OnShown(e);
        m = new Mutex(true, "frmAdmin");
    }

    //This 'OnClosed' event is skipped when this application is terminated using only Exit(); therefore, call Close() before calling Exit().
    //The 'catch' code is added to insure the program keeps running in the event these exceptions occur.
    protected override void OnClosed(EventArgs e)
    {
        if (m != null)
        {
            try
            {
                base.OnClosed(e);
                m.ReleaseMutex();
                m.Close(); 
            }
            catch (AbandonedMutexException)
            {
                //This catch is included to insure the program keeps running in the event this exception occurs.
            }
            catch (ApplicationException)
            {
                //This catch is included to insure the program keeps running in the event this exception occurs.
            }
            catch (SynchronizationLockException)
            {
                //This catch is included to insure the program keeps running in the event this exception occurs.
            }
        }
    }

Мьютекс используется в frmTimer следующим образом:

private void tmTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    bool adminIsOpen = false;
    Mutex _muty = null;
    try
     {
        //If the named mutex does not exist then OpenExisting will throw the 'WaitHandleCannotBeOpenedException',
        //otherwise the mutex exists and Admin is open.
        _muty = Mutex.OpenExisting("frmAdmin");
        adminIsOpen = true;
        _muty.Close();
    }
    catch (WaitHandleCannotBeOpenedException)
    {
        //This catch is thrown when Admin is not opened (keep 'adminIsOpen = false'). Do not delete this catch.
    }
    catch (AbandonedMutexException)
    {
        //This catch is included to insure the program keeps running in the event this exception occurs.
    }

    if (adminIsOpen == false)
    {
        //frmAdmin is closed; go ahead and open frmUser.
        <<Code snipped>>
    }
}

Ответы [ 2 ]

3 голосов
/ 18 июля 2010

Проблема в обработчике событий Elapsed, он проверяет, существует ли мьютекс с помощью Mutex.OpenExisting ().Конечно, это существует.Вы на самом деле не проверяете, сигнализировано ли это.Это требует вызова метода WaitOne (0).

Также следует помнить, что создание формы в событии Timer.Elapsed совершенно неуместно.Это событие запускает поток пула потоков, оно совсем не подходит для работы в качестве потока пользовательского интерфейса.Он имеет неправильное состояние COM ([STAThread] и Thread.SetApartmentState), свойство, которое нельзя изменить в потоке пула потоков.Вместо этого используйте обычный Form.Timer, чтобы форма создавалась в потоке пользовательского интерфейса программы.

Редактировать: также остерегаясь неизбежной гонки, таймер может создать форму пользователя за одну микросекунду до Форма администратора закрывается.Другими словами, у вас будет форма пользователя без формы администратора, единственное условие, которое вы написали для предотвращения этого кода.Это уместно?Пытаться влиять друг на друга в разных процессах - плохая идея ...

3 голосов
/ 18 июля 2010

Проблема в том, что после запуска приложения администратора Mutex существует, а затем OpenExisting завершается успешно. Выпуск Mutex не разрушает объект Kernel, он просто освобождает удержание мьютекса, чтобы другие ожидающие потоки могли выполняться. Поэтому последующие вызовы Mutex.OpenExisting успешно открывают мьютекс.

Возможно, вы захотите использовать Mutex.WaitOne (TimeSpan) , если вы успешно откроете Mutex и если WaitOne вернет false, то вы знаете, что не могли получить мьютекс, поэтому приложение Admin все еще удерживает мьютекс.

...