• 线程、同步与锁——Mutex想说爱你不容易


    除了Lock()、Monitor之外,我们最长用的就是Mutex了,但是玩不好Mutex就总会造成死锁或者AbandonedMutexException(我就玩的不怎么好,在并发性访问测试的时候总是遇到关于Mutex的问题,各位线虫见笑了,不过还是把我遇到的一些问题和总结拿出来和大家分享,有误的地方还往指正。

    还是先举一个简单的例子,来说明一下这个东西:

     

       public class ThreadMutex

        {


            
    public void Test()

            {

                Thread t1 
    = new Thread(Thread1);

                Thread t2 
    = new Thread(Thread2);

                t1.Start();

                t2.Start();

            }

            
    public void Thread1()

            {

                Mutex m 
    = new Mutex(false"test");

                
    bool b2 = m.WaitOne();

                Console.WriteLine(
    "Thread1 get the mutex : " + b2);

                Thread.Sleep(
    10000);

                m.ReleaseMutex();

            }

            
    public void Thread2()

            {

                Mutex m 
    = new Mutex(false"test");

                
    bool b2 = m.WaitOne();

                Console.WriteLine(
    "Thread2 get the mutex : " + b2);

                Thread.Sleep(
    1000);

                m.ReleaseMutex();

                

            }

    }

    恩,Thread1Mutex.WaitOne()后,就想到与Thread1拿到了Mutex所有权,这时Thread2得到了同样的Mutex,然后Mutex.WaitOne(),也想拿到Mutex的所有权,这时就必须等待了。这里只需要两点就能明白什么是Mutex了:

    1.   Mutex是一个令牌,当一个线程拿到这个令牌时运行,另外想拿到令牌的线程就必须等待,直到拿到令牌的线程释放令牌。没有所有权的线程是无法释放令牌的。

    2.   Mutexfalsestring)中的string是令牌的关键,或者可以叫令牌名,因为Mutex是跨进程的,整个系统中只会有唯一的令牌存在所以,也就是说你在一个应用程序中的一个线程中得到了Mutex的所有权,那在另外一个线程中的另外的线程想得到他就必须要等待。

     

    要弄清楚Mutex就还需要弄清楚两个很重要的问题:

    1.那就是Mutex是调用的Win32 API 

    HANDLE CreateMutex(

       LPSECURITY_ATTRIBUTES lpMutexAttributes,

       BOOL bInitialOwner,

       LPCTSTR lpName

    );

    这就是他为什么能跨进程访问的原因,正是由于它使用P/Invoke,他的效率问题就凸现出来,明显不如Monitor之类的快,用的时候还需多多斟酌。

     

    下面放一个Mutex的简单实现,看看Mutex.net下是如何实现的。

     

    2Mutex的生命周期,这个问题让我郁闷了很久,因为不太了解Mutex的机制,使得我也没法弄清楚到底能活多长时间,这也是AbandonedMutexException经常会出现的原因。还是先来看一段程序:

     

      public class ThreadMutex

        {

            
    public void Test()

            {

                Thread t1 
    = new Thread(Thread1);

                Thread t2 
    = new Thread(Thread2);

                t1.Start();

                t2.Start();

            }

            
    public void Thread1()

            {

                Mutex m 
    = new Mutex(false"test");

                
    bool b2 = m.WaitOne();

                Console.WriteLine(
    "Thread1 get the mutex : " + b2);

            }

            
    public void Thread2()

            {

                Thread.Sleep(
    10);//保证Thread1执行完

                Mutex m 
    = new Mutex(false"test");

                
    bool b2=m.WaitOne();

                Console.WriteLine(b2);

                m.ReleaseMutex();

            }

    }

    Thread2中的WaitOne()方法就会报错了,AbandonedMutexException,原因就是Thread1拿到了Mutex后没有释放,Thread1就结束了,这样Mutex成了被抛弃的地孩子了,呵呵。但是如果垃圾收集了,就不一样咯。代码稍微修改了一下:

     

      public class ThreadMutex

        {

            
    public void Test()

            {

                Thread t1 
    = new Thread(Thread1);

                Thread t2 
    = new Thread(Thread2);

                t1.Start();

                t2.Start();

            }

            
    public void Thread1()

            {

                Mutex m 
    = new Mutex(false"test");

                
    bool b2 = m.WaitOne();

                Console.WriteLine(
    "Thread1 get the mutex : " + b2);

            }

            
    public void Thread2()

            {

                Thread.Sleep(
    10);//保证Thread1执行完

                GC.Collect();

                GC.WaitForPendingFinalizers();

                
    bool b1;

                Mutex m 
    = new Mutex(false"test",out b1);

                Console.WriteLine(b1);

                
    bool b2=m.WaitOne();

                Console.WriteLine(b2);

                m.ReleaseMutex();

                

            }

        }

    结果是:

    Thread1 get the mutex : True

    True

    True

    Thread2里面的Mutex是新创建的,呵呵,这里面的玄妙自己体会吧。

     

    最后要说一下的是Mutex的访问和window访问文件的机制基本上是一样的,window访问对象和访问文件使用的是同样的安全机制(虽然我还没看懂)。
  • 相关阅读:
    2016.7.22.noip2012D2
    2016.7.21.noip2014D2
    LIS最长上升子序列O(n^2)与O(nlogn)的算法
    vijos1910解方程
    vijos1909寻找道路
    viojs1908无线网路发射器选址
    P1907飞扬的小鸟
    P1906联合权值
    P1905生活大爆炸版 石头剪刀布
    poj1274(匈牙利算法)
  • 原文地址:https://www.cnblogs.com/hanmos/p/2055769.html
Copyright © 2020-2023  润新知