.NET 同步与异步 之 Mutex (十二)

本随笔续接:.NET 同步与异步 之 线程安全的集合 (十一)html

本随笔 及 接下来的两篇随笔,将介绍 .NET 同步与异步系列 的最后一个大块知识点:WaitHandle家族。编程

抽象基类:WaitHandle, 三个子类: EventWaitHandle(Event通知) 、Mutex(进程同步锁)、Semaphone (信号量),还有两个孙子辈:System.Threading.AutoResetEventSystem.Threading.ManualResetEvent,都是 EventWaitHandle 的子类。安全

 

1、抽象基类 WaitHandle

[ComVisibleAttribute(true)]
public abstract class WaitHandle : MarshalByRefObject, IDisposable

经过上面的信息,咱们能够知道 WaitHandle  继承自 MarshalByRefObject, 并实现了 IDisposable 接口。app

对于 MarshalByRefObject ,你也许不是很熟悉,但它的不少子类你必定会用过的,让咱们来揭开它的庐山真面目。异步

在MSND中是这样描述 MarshalByRefObject 的:ide

应用程序域是一个操做系统进程中一个或多个应用程序所驻留的分区。同一应用程序域中的对象直接通讯。不一样应用程序域中的对象的通讯方式有两种:一种是跨应用程序域边界传输对象副本,一种是使用代理交换消息。MarshalByRefObject 是经过使用代理交换消息来跨应用程序域边界进行通讯的对象的基类。函数

看到这里你也许更迷惑了,我用过它? 用过它的子类? 没错,就是用过它的子类,而且还不少。post

例如 System.Drawing命名空间的 Brush、Image、Pen、Font 等等,还有个你们更熟悉的 System.IO命名空间下的Stream.ui

延展阅读:利用 MarshalByRefObject 实现 AOP this

看到这里咱们只须要知道 WaitHandle 具备跨应用程序域进行通信的能力就能够了。

 

2、Mutex(进程同步锁)

一、MSDN对Mutex的定义为进程间的同步基元, 即锁的概念。

  反观Monitor、平时只用来在应用程序域内的线程之间通讯。其实,若是用于锁的对象派生自MarshalByRefObject,Monitor 也可在多个应用程序域中提供锁定。

  Mutex因为须要调用操做系统资源,所以执行的开销比Monitor大得多,因此若是仅仅须要在应用程序内部的线程间同步操做,Monitor/lock应当是首选

 

二、Mutex 的用法

  • WaitOne() /WaitOne(TimeSpan, Boolean)及若干个重载:请求全部权,该调用会一直阻塞到当前 mutex 收到信号,或直至达到可选的超时间隔,这几个方法都不须要提供锁定对象做为额外参数。
    • 您可使用 WaitHandle.WaitOne 请求全部权的互斥体的方法。 调用线程受到阻止,直到发生下列状况之一︰
    • 互斥体发出信号以指示不拥有。 在此状况下, WaitOne 方法将返回 true, ,调用线程的互斥体全部权,并访问由 mutex 保护的资源。 线程完成后访问资源,必须调用 ReleaseMutex 方法来释放 mutex 的全部权。 

    • 对调用中指定的超时间隔 WaitOne 具备方法 millisecondsTimeout 或 timeout 参数已过。 在此状况下, WaitOne 方法将返回 false, 此时该线程不会获取互斥体的全部权。

  • ReleaseMutex():释放当前 Mutex 一次。注意,这里强调了一次,由于拥有互斥体的线程能够在重复的调用WaitOne系列函数而不会阻止其执行;这个跟Monitor的Enter()/Exit()能够在获取对象锁后能够被重复调用同样。Mutex被调用的次数由公共语言运行库(CLR)保存,每WaitOne()一次计数+1,每ReleaseMutex()一次计数-1,只要这个计数不为0,其它Mutex的等待者就会认为这个Mutex没有被释放,也就没有办法得到该Mutex。 另外,跟Monitor.Exit()同样,只有Mutex的拥有者才能RleaseMutex(),不然会引起异常。
  • 若是线程在拥有互斥体时终止,咱们称此互斥体被遗弃(Abandoned)。在MSDN里,微软以警告的方式指出这属于“严重的”编程错误。这是说拥有mutex的拥有者在得到全部权后,WaitOne()和RelaseMutex()的次数不对等,调用者自身又不负责任地停止,形成mutex 正在保护的资源可能会处于不一致的状态。其实,这无非就是提醒你记得在try/finally结构中使用Mutex

 

三、全局和局部的Mutex

若是在一个应用程序域内使用Mutex,固然不如直接使用Monitor/lock更为合适,由于前面已经提到Mutex须要更大的开销而执行较慢。不过Mutex毕竟不是Monitor/lock,它生来应用的场景就应该是用于进程间同步的。用于在进程间通信的Mutex咱们称为全局Mutex,而只用于在应用程序域内部通信的Mutex、咱们称为局部Mutex.

全局Mutex和局部Mutex是经过构造函数来构造不一样的实例的,让咱们来看一下Mutex的构造函数,一共有5个,挑两个具备表明性的看一下吧:

  • Mutex():用无参数的构造函数获得的Mutex没有任何名称,而进程间没法经过变量的形式共享数据,因此没有名称的Mutex也叫作局部(Local)Mutex。另外,这样建立出的Mutex,建立者对这个实例并无拥有权,仍然须要调用WaitOne()去请求全部权。
  • Mutex(Boolean initiallyOwned, String name, out Booldan createdNew, MutexSecurity):第一个bool参数:指示初始化的实例是否拥有互斥体全部权。第二个string类型、为互斥体指定一个名称,若是string为null或者空字符串 则至关于建立一个没有名字的Mutex,当属于局部Mutex. 而有名字的Mutex当属于全局Mutex.第三个bool参数、若是已经初始化了互斥体 返回True, 若是互斥体已经存在则返回False. 最后一个参数用于Mutex访问的安全性控制。

 

四、用途 

Mutex天生为进程间的同步基元,所以它能够用来控制应用程序的单实例

/// <summary>
/// 单实例运行
/// </summary>
/// <returns> true 应用程序已启动,false 则没有 </returns>
public bool SingleRun(ref System.Threading.Mutex mutex )
{
    mutex = new System.Threading.Mutex(false, "WINDOWS");
    if (!mutex.WaitOne(0, false))
    {
        mutex.Close();
        mutex = null;
    }
    if (mutex == null)
    {
        return true;
    }
    return false;
}
进程单实例

 

 

未完待续,下一篇随笔: EventWaitHandle(Event通知) 

附,Demo : http://files.cnblogs.com/files/08shiyan/ParallelDemo.zip

参见更多:随笔导读:同步与异步

相关文章
相关标签/搜索