线程、同步与锁——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();

            

        }

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

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

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

 

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

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

HANDLE CreateMutex(

   LPSECURITY_ATTRIBUTES lpMutexAttributes,

   BOOL bInitialOwner,

   LPCTSTR lpName

);

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

 

 

 

 

 

 

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

 

2.Mutex的生命周期,这个问题让我郁闷了很久,因为不太了解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访问对象和访问文件使用的是同样的安全机制(虽然我还没看懂)。
0
0
(请您对文章做出评价)
« 上一篇: 线程,同步与锁————Lock你到底锁住了谁
» 下一篇: 线程、同步与锁——EventWaitHandle实战数据缓存

Feedback

#1楼   回复  引用  查看    

2007-02-02 18:14 by idior       
Mutex的一个特点就是可以实现进程间的同步,甚至是两个远程进程的同步。如果不是这两种情况,自然还是用Monitor比较方便。

有关多线程同步问题
volatile
System.Threading.Interlocked
Monitor(lock)
Mutex
Events
Semaphores
System.Threading.ReaderWriterLock
System.Runtime.Remoting.Contexts.SynchronizationAttribute

楼主可以按着顺序一个个介绍,呵呵。
忘了还有COM+中的System.EnterpriseServices.SynchronizationAttribute

#2楼   回复  引用  查看    

2007-02-02 20:25 by charleschen       
Mutex的用途在多进程安全。

#3楼   回复  引用  查看    

2007-02-02 21:52 by 双鱼座       
Mutex其实并不常用,主要用于进程边界的同步,没有人会在可以用Monitor解决的地方换成Mutex。如果Minitor解决不了的时候还可以用EventWaitHandle(二态)或者Semaphore(多态)。使用Mutex慢并不是因为P/Invoke(CLI对Windows的十种内核对象的包装都无一例外是通过P/Invoke实现的,并不独独只有Mutex),通常在原生Windows情况下Mutex的创建都需要差不多600个时钟,而Monitor(CriticalSection)只需要6个时钟。所以,不是必须,没有人会用的。不必因为没有完全弄懂就对Mutex说三道四。

#4楼[楼主]   回复  引用  查看    

2007-02-02 22:40 by City22       
@双鱼座
呵呵,受教了
我开始就说了,是工作总结,不敢说三道四的,没有打算教别人的意思。

#5楼   回复  引用  查看    

2007-03-11 10:58 by 阿牛       
线程同步用Mutex,太浪费了吧。还是,如果用,最好用 try{}finally{}的形式。

#6楼   回复  引用  查看    

2008-09-22 16:10 by 想你因为喝酒       
在Thread2中的WaitOne()方法报错的原因是CLR对字符串的暂留,导致两个"test"指向同一个对象,结果前一线程没执行完,后一线程就对同一"test"对象锁定,当然会报错。这也是为什么你用mutex会经常死锁的原因!

#7楼   回复  引用    

2008-12-31 16:01 by AA22s[未注册用户]
lz对Mutex也不是太熟悉阿。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值