互斥不释放

时间:2010-07-18 12:42:10

标签: c# winforms mutex

我的c#WinForm解决方案包含几个项目,包括一个包含frmAdmin的Admin项目和一个包含frmUser的User项目。第三个项目包含frmTimer,它有一个定时启动frmUser的计时器。

我希望frmTimer在frmAdmin打开时不启动frmUser。

如果frmAdmin打开,我正在使用一个名为mutex来告诉frmTimer;但是,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>>
        }
    }

当我运行应用程序时,每次计时器触发时都会出现带有“Debug 4”文本的消息框,直到我打开frmAdmin(在密码验证后从frmLogin启动frmAdmin),然后在带有“Debug 3”的消息框上打开即使在我退出frmAdmin之后,每次计时器触发时都会出现文本。退出frmAdmin时,我看到带有“Debug 2”文本的消息框。我从未见过带有'Debug 1'文本的消息框(或输出窗口消息)。

似乎在frmAdmin关闭后互斥锁不会释放,这会阻止frmUser启动。

感谢任何帮助。

这是this问题的后续问题。

更新

这是我的代码,让它开始工作。我得到了它的工作,因为Hans Passant和Chris Taylor以及来自this帖子的Serhio的答案。

现在在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 个答案:

答案 0 :(得分:3)

问题是,一旦运行管理应用程序,Mutex就会存在,然后OpenExisting会成功。释放互斥锁不会破坏内核对象,它只是释放互斥锁上的保留,以便其他等待的线程可以执行。因此,随后的Mutex.OpenExisting调用会成功打开互斥锁。

如果您成功打开Mutex并且WaitOne返回false,您可能想要使用Mutex.WaitOne(TimeSpan),那么您知道您无法获取互斥锁,因此Admin应用程序仍然保留互斥锁。

答案 1 :(得分:3)

问题在于Elapsed事件处理程序,它使用Mutex.OpenExisting()检查互斥锁是否存在。当然存在。您实际上并未检查是否已发出信号。这需要调用WaitOne(0)方法。

还要注意在Timer.Elapsed事件中创建表单是不合适的。该事件运行一个线程池线程,它完全不适合充当UI线程。它具有错误的COM状态([STAThread]和Thread.SetApartmentState),这是一个在线程池线程上无法更改的属性。使用常规的Form.Timer,以便在程序的UI线程上创建表单。

编辑:还要注意不可避免的竞争,计时器可以在管理表单关闭之前创建一个微秒的用户表单。换句话说,您将拥有一个没有Admin表单的User表单,这是您编写此代码以防止的一个条件。这合适吗?在不同的过程中尝试形式互相影响是一个坏主意......