互斥不释放

我的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(); <> } 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(); } <> } 

最初,我在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. <> } } 

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

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

任何帮助表示赞赏。

这是这个问题的后续问题。

UPDATE

在使用它之后,这是我的代码。 我得到了它的工作,因为汉斯帕斯特和克里斯泰勒和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. <> } } 

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

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

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

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

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