问题描述
我的C#WinForm的解决方案包含多个项目,包括含有frmAdmin的管理项目,并含有frmUser用户项目。第三个项目包含frmTimer有一个计时器,定期推出frmUser。
我要frmTimer不推出frmUser时frmAdmin是开放的。
我使用了一个名为互斥告诉frmTimer如果frmAdmin是开放的;然而,该互斥出现frmAdmin关闭后不被释放。
互斥是frmAdmin创造了这样的代码:
公共部分类frmAdmin:表
{
互斥米;
保护覆盖无效OnShown(EventArgs的发送)
{
base.OnShown(E);
M =新的Mutex(真的,frmAdmin);
}
保护覆盖无效OnClosed(EventArgs的发送)
{
base.OnClosed(E);
m.ReleaseMutex();
MessageBox.Show(调试1 - 在frmAdmin ONCLOSED事件。); //测试代码
的Debug.WriteLine(调试1 - 在frmAdmin ONCLOSED事件。); //测试代码
}
公共frmAdmin(字符串strPassedFromLogin)
{
的InitializeComponent();
<<代码剪断>>
}
私人无效frmAdmin_FormClosing(对象发件人,FormClosingEventArgs E)
{
//开始增加_
布尔mutexSet = TRUE;
试
{
Mutex.OpenExisting(frmAdmin);
MessageBox.Show(调试2 - 在frmAdmin的FormClosing事件。); //测试代码
}
赶上(WaitHandleCannotBeOpenedException)
{
mutexSet = FALSE;
}
如果(mutexSet)
{
base.OnClosed(E);
m.ReleaseMutex();
}
//结束_加
Application.Exit();
}
<<代码剪断>>
}
起初,我并没有在frmAdmin_FormClosing方法的任何互斥代码(该方法仅包含Application.Exit()线)。我添加了互斥代码,试图释放互斥锁,但它仍然没有被释放。
互斥在frmTimer使用这样的:
私人无效tmTimer_Elapsed(对象发件人,System.Timers.ElapsedEventArgs E)
{
布尔adminIsOpen = TRUE;
试
{
Mutex.OpenExisting(frmAdmin);
MessageBox.Show(调试3 - 互斥存在:frmAdmin是开放的。); //测试代码
}
赶上(WaitHandleCannotBeOpenedException)
{
adminIsOpen = FALSE;
MessageBox.Show(调试4 - 互斥不存在:frmAdmin未打开。); //测试代码
}
如果(adminIsOpen ==假)
{
// frmAdmin被关闭;继续前进,打开frmUser。
<<代码剪断>>
}
}
当我运行应用程序,以在MessageBox的'调试4调试3'文本每次出现定时器触发文本中,每个定时器触发,直到我打开frmAdmin(frmAdmin从frmLogin密码验证后推出),从此与该消息框出现时间',即使我退出frmAdmin。当退出frmAdmin,我看到了调试2文本在MessageBox。我从来没有见过在MessageBox(或输出窗口消息)与调试1的文字。
看来好像互斥不frmAdmin是释放后关闭,这样可以防止frmUser发动。
任何帮助表示赞赏。
这是一个后续问题来
更新
下面是得到它的工作后,我的代码。我得到了它,因为从汉斯帕桑特和克里斯·泰勒和Serhio从的后
该互斥锁现在frmAdmin创造了这样的代码:
互斥米;
保护覆盖无效OnShown(EventArgs的发送)
{
base.OnShown(E);
M =新的Mutex(真的,frmAdmin);
}
//此应用程序时使用唯一的出口终止这种OnClosed事件被跳过();因此,调用Close()调用exit()之前。
//在'抓'的代码被添加到确保程序在发生这些异常事件保持运行。
保护覆盖无效OnClosed(EventArgs的发送)
{
如果(M!= NULL)
{
试
{
base.OnClosed (E);
m.ReleaseMutex();
m.Close();
}
赶上(AbandonedMutexException)
{
//这渔获包括以确保该计划在这个异常发生的情况下保持运行。
}
赶上(ApplicationException的)
{
//这渔获包括以确保该计划在这个异常发生的情况下保持运行。
}
赶上(SynchronizationLockException)
{
//这渔获包括以确保该计划在这个异常发生的情况下保持运行。
}
}
}
互斥在frmTimer使用像这样的:
私人无效tmTimer_Elapsed(对象发件人,System.Timers.ElapsedEventArgs E)
{
布尔adminIsOpen = FALSE;
互斥_muty = NULL;
试
{
//如果命名互斥不存在,则OpenExisting会抛出WaitHandleCannotBeOpenedException',
//否则存在互斥和Admin是开放的。
_muty = Mutex.OpenExisting(frmAdmin);
adminIsOpen = TRUE;
_muty.Close();
}
赶上(WaitHandleCannotBeOpenedException)
{
//当管理员没有打开(保持'adminIsOpen =假),该抓被抛出。不要删除此捕捞。
}
赶上(AbandonedMutexException)
{
//这渔获包括以确保该计划在这个异常发生的情况下保持运行。
}
如果(adminIsOpen ==假)
{
// frmAdmin被关闭;继续前进,打开frmUser。
<<代码剪断>>
}
}
的问题是,在经过的事件处理程序,它会检查互斥的存在的有Mutex.OpenExisting()。当然它的存在。你实际上并没有检查,如果它发出信号。这需要调用它的WaitOne(0)方法。
另外要注意,在Timer.Elapsed事件创建一个表单是很不合适的。该事件运行一个线程池线程,它是不太适合充当UI线程。它有错误的COM状态([STAThread]和Thread.SetApartmentState),你不能在一个线程池线程更改属性。 。这样的形式大干快上程序的UI线程创建使用常规Form.Timer而不是
编辑:提防也不可避免的比赛,计时器可以创建用户形成一个微秒的前的管理员窗体关闭。换句话说,你将有一个用户表单没有Admin的形式,有一个条件,你写了这个代码,以防止。是不是合适?在不同的进程试图形式相互影响是一个坏主意...
My c# WinForm solution contains several projects including an Admin project containing frmAdmin and a User project containing frmUser. A third project contains frmTimer that has a timer that periodically launches frmUser.
I want frmTimer to not launch frmUser when frmAdmin is open.
I'm using a named mutex to tell frmTimer if frmAdmin is open; however, the mutex appears not to be released after frmAdmin is closed.
The mutex is created in frmAdmin with code like this:
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>>
}
Initially, I did not have any mutex code in the frmAdmin_FormClosing method (the method only contained the Application.Exit() line). I added the mutex code in an attempt to release the mutex, but it is still not being released.
The mutex is used in frmTimer like this:
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>>
}
}
When I run the application, the messagebox with the 'Debug 4' text appears each time the timer fires until I open frmAdmin (frmAdmin is launched from frmLogin after password verification), from then on the messagebox with the 'Debug 3' text appears each time the timer fires, even after I exit frmAdmin. When exiting frmAdmin, I see the messagebox with the 'Debug 2' text. I've never seen the messagebox (or an output window message) with the 'Debug 1' text.
It appears as though the mutex doesn't release after frmAdmin is closed and this prevents frmUser from launching.
Any help is appreciated.
This is a follow-up question to this question.
UPDATE
Here is my code after getting it to work. I got it to work because of the answers from Hans Passant and Chris Taylor and from Serhio from this post.
The mutex is now created in frmAdmin with code like this:
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.
}
}
}
The mutex is used in frmTimer like this:
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>>
}
}
The problem is in the Elapsed event handler, it checks if the mutex exists with Mutex.OpenExisting(). Sure it exists. You are not actually checking if it is signaled. That takes calling its WaitOne(0) method.
Also beware that creating a form in a Timer.Elapsed event is quite inappropriate. That event runs a threadpool thread, it is not at all suitable to act as a UI thread. It has the wrong COM state ([STAThread] and Thread.SetApartmentState), a property you cannot change on a threadpool thread. Use a regular Form.Timer instead so that the form gets created on program's UI thread.
Edit: also beware of the inevitable race, the timer could create the User form one microsecond before the Admin form closes. In other words, you'll have a User form without an Admin form, the one condition you wrote this code to prevent. Is that appropriate? Trying forms in different processes to affect each other is a bad idea...
这篇关于互斥锁没有释放的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!