互斥体(mutex)代表一个互斥的锁。互斥体有一些额外的逻辑,这造成它们比其他构造更复杂。首先,Mutex对象会查询调用线程的Int32 ID,记录是哪个线程获得了它。一个线程调用ReleaseMutex时,Mutex确保调用线程就是获取Mutex的那个线程。如若不然,Mutex对象的状态就不会改变,而ReleaseMutex会抛出一个System.ApplicationException。另外,拥有Mutex的线程因为任何原因而终止,在Mutex上等待的某个线程会因为抛出System.Threading.AbandonedMutexException异常而被唤醒。该异常通常会成为未处理的异常,从而终止整个进程。这是好事,因为线程在获取了一个Mutex之后,可能在更新完Mutex所保护的数据之前终止。如果其他线程捕捉了AbandonedMutexException,就可能试图访问损坏的数据,造成无法预料的结果和安全隐患。
示例
using System;
using System.Threading;
namespace MutexTest
{
class Program
{
static void Main(string[] args)
{
SomeClass sc = new SomeClass();
Thread myThread;
Random rnd = new Random();
for (int i = 0; i < 5; i++)
{
myThread = new Thread(new ThreadStart(sc.Method1));
myThread.Name = String.Format("Thread{0}", i + 1);
//等待一会再启动线程
Thread.Sleep(rnd.Next(0, 1000));
myThread.Start();
}
Console.ReadKey();
}
}
internal class SomeClass : IDisposable
{
//Mutex对象维护着一个递归计数(recursion count)
//调用1次WaiOne()计数增加1
//调用1次ReleaseMutex()计数减少1
//只有计数变成0,另一个线程才能成为该Mutex的所有者
private readonly Mutex m_lock = new Mutex();
public void Method1()
{
m_lock.WaitOne();
//随便做些事情...
Console.WriteLine("{0} Method1 do something...", Thread.CurrentThread.Name);
Method2();//Method2递归地获取锁
m_lock.ReleaseMutex();
}
public void Method2()
{
m_lock.WaitOne();
//随便做些事情...
Console.WriteLine("{0} Method2 do something...", Thread.CurrentThread.Name);
m_lock.ReleaseMutex();
}
public void Dispose()
{
m_lock.Dispose();
}
}
}
运行测试