Mutex的使用

什么是Mutex

“mutex”是术语“互相排斥(mutually exclusive)”的简写形式,也就是互斥量。互斥量跟临界区中提到的Monitor很相似,只有拥有互斥对象的线程才具有访问资源的权限,由于互斥对象只有一个,因此就决定了任何情况下此共享资源都不会同时被多个线程所访问。当前占据资源的线程在任务处理完后应将拥有的互斥对象交出,以便其他线程在获得后得以访问资源。

Mutex的用途

  Mutex并不适合于有相互消息通知的同步;另一方面而我们也多次提到局部Mutex应该被Monitor/lock所取代;而跨应用程序的、相互消息通知的同步由将在后面讲到的EventWaiteHandle/AutoResetEvent/ManualResetEvent承担更合适。所以,Mutex在.net中应用的场景似乎不多。不过,Mutex有个最常见的用途:用于控制一个应用程序只能有一个实例运行。

using System;
using System.Threading;

class MutexSample
{
    private static Mutex mutex = null;  //设为Static成员,是为了在整个程序生命周期内持有Mutex

    static void Main()
    {
        bool firstInstance;
       
        mutex = new Mutex(true, @"Global\MutexSampleApp", out firstInstance);
        try
        {
            if (!firstInstance)
            {
                Console.WriteLine ("已有实例运行,输入回车退出……");
                Console.ReadLine();
                return;
            }
            else
            {
                Console.WriteLine ("我们是第一个实例!");
                for (int i=60; i > 0; --i)
                {
                    Console.WriteLine (i);
                    Thread.Sleep(1000);
                }
            }
        }
        finally
        {
            //只有第一个实例获得控制权,因此只有在这种情况下才需要ReleaseMutex,否则会引发异常。
            if (firstInstance)
            {
                mutex.ReleaseMutex();
            }
            mutex.Close();
            mutex = null;
        }
    }
}

  这是一个控制台程序,你可以在编译后尝试一次运行多个程序,结果当然总是只有一个程序在倒数计时。你可能会在互联网上找到其它实现应用程序单例的方法,比如利用 Process 查找进程名、利用Win32 API findwindow 查找窗体的方式等等,不过这些方法都不能保证绝对的单例。因为多进程和多线程是一样的,由于CPU时间片随机分配的原因,可能出现多个进程同时检查到没有其它实例运行的状况。这点在CPU比较繁忙的情况下容易出现,现实的例子比如傲游浏览器。即便你设置了只允许一个实例运行,当系统比较忙的时候,只要你尝试多次打开浏览器,那就有可能“幸运”的打开若干独立的浏览器窗口。

  别忘了,要实现应用程序的单例,需要在在整个应用程序运行过程中都保持Mutex,而不只是在程序初始阶段。所以,例子中Mutex的建立和销毁代码包裹了整个Main()函数。

使用Mutex需要注意的两个细节

  1. 可能你已经注意到了,例子中在给Mutex命名的字符串里给出了一个“Global\”的前缀。这是因为在运行终端服务(或者远程桌面)的服务器上,已命名的全局 mutex 有两种可见性。如果名称以前缀“Global\”开头,则 mutex 在所有终端服务器会话中均为可见。如果名称以前缀“Local\”开头,则 mutex 仅在创建它的终端服务器会话中可见,在这种情况下,服务器上各个其他终端服务器会话中都可以拥有一个名称相同的独立 mutex。如果创建已命名 mutex 时不指定前缀,则它将采用前缀“Local\”。在终端服务器会话中,只是名称前缀不同的两个 mutex 是独立的 mutex,这两个 mutex 对于终端服务器会话中的所有进程均为可见。即:前缀名称“Global\”和“Local\”仅用来说明 mutex 名称相对于终端服务器会话(而并非相对于进程)的范围。最后需要注意“Global\”和“Local\”是大小写敏感的。
  2. 既然父类实现了IDisposalble接口,那么说明这个类一定需要你手工释放那些非托管的资源。所以必须使用try/finally,亦或我讨厌的using,调用Close()方法来释放Mutex所占用的所有资源!

参考

https://www.cnblogs.com/suntp/p/8258488.html

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值