Mutex是从WaitHandle派生的类,保证了多个线程在某个资源或代码块上互相排斥。Mutex定义如下:
Mutex的实例为句柄分配了两个逻辑意义:被占有和不被占有,也就是在任何时候都只能被一个线程所拥有。当一个线程试图申请Mutex,而它此时被其它线程占有,则该线程被阻塞,直到Mutex的所有者调用ReleaseMutex()让出所有权。
从定义中可以看出,Mutex的构造函数有多种重载,默认构造函数创建的Mutex为不占用状态,本次着重介绍第3种重载。
参数含义如下:
bool initiallyOwned : 接受布尔值,为true表示创建的Mutex对象所有权归创建线程所有,反之亦然;
string name : 为Mutex实例对象指定一个唯一的名称,称为命名的Mutex,稍后将会使用到;
上文提到,当一个线程试图访问已被占有的Mutex时,会阻塞当前线程的执行,这时,可使用方法WaitOne()等待,WaitOne也有很多重载版本,因为本文着重介绍应用程序的单例模式,所以只使用到了其中一个版本,定义如下:
WaitOne(Int32 , bool exitContext) | 阻止当前线程,直到当前 Mutex可用,同时使用 32 位带符号整数测量时间间隔。 |
或
WaitOne(TimeSpan , bool exitContext)) | 阻止当前线程,直到当前 Mutex可用,同时使用 TimeSpan 测量时间间隔。 |
bool exitContext 的说明不在本文的论述范围内。使用时将其设置为false即可;
下面简要提一下上文中提到的"命名的Mutex",在第3中构造函数中,允许为Mutex实例对象提供一个全局唯一的名字,默认情况下,它是没有名字的。当你为它提供一个名称后,机器上的任何线程,包括在其他应用程序域或进程中的线程都可以访问该命名的Mutex。在指定名称时,操作系统会检查是否已经有其他人创建了同名的Mutex,如果有,就给创建者线程一个本地对象来表示全域Mutex。一个命名的Mutex允许跨进程和跨应用程序域进行通信(这有点类似于IPC,当然他们是不能相提并论的!),此时,initiallyOwned应该设置为false,这是很必要的。
下面要进行今天的主题了(单例应用程序)
用过MS outlook,和网易有道词典的应该都知道,当你已经打开一个实例时,此时你又点击应用图标试图再次打开,这时,程序并没有如愿打开,而是切换到了已经存在的程序界面,这就是单例程序,程序如其名,单例,也就是单个实例。
下面看一段代码:
这段很熟悉的代码就是在创建WinForm项目的时候自动生成的,不同的是原来的Application已经改为了SingletonApp,下面是SingletonApp的定义:
当没有应用程序的其他实例在运行,窗体就会显示出来成功运行,如果已经存在该程序的实例,则会显示一条提示信息,然后退出执行。
在内部,SingletonApp使用了Application类,如果启动的是唯一的实例,它就将run的实现委托给这个类,反之,则放弃执行。
当单例程序关闭时,它必须释放Mutex的所有权,新实例才能得以执行,幸运的是,Application类提供了ApplicationExit事件,用于发出应用程序关闭的信号,SingletonApp类订阅了该事件,当单例程序退出之前将释放命名Mutex的所有权,然后关闭应用程序。