替代object加锁方式
使用System.object对象作为线程同步的工具,建立了一个基本的锁机制,确保资源只能同时被一个线程所访问。
但是这个对象不作任何其他用途,知识用于锁机制。
如果有一个类型可以专注于为线程同步的锁机制和信号量机制提供服务,那么上面的代码就可以简化。
.net中提供了更强大的system.threading.waithandle及其子类型,可以实现类似的效果。
首先来看Mutex是如何取代object的:
//System.Threading.Mutex 用于锁机制,同一时刻只能有一个线程拥有它,只有等到该线程释放,其他线程才能持有它。
//因此,使用mutex可以完成和lock语句相同的功能。
//对于mutex来说,waitone方法为获取互斥体
//(等待其他线程发出释放互斥体信号,如果没有任何其他线程占有互斥体,则调用waitone的线程获取到互斥体)
//releaseMutex方法则用于释放互斥体
namespace 使用Mutex
{
class Program
{
private string called = "";
private System.Threading.Mutex mtx = new System.Threading.Mutex();//使用互斥体
static void Main(string[] args)
{
Program p = new Program();
Thread.CurrentThread.Name = "main ";
Thread worker = new Thread(p.ThreadEntry);
worker.Name = "worker ";
worker.Start();
p.ThreadEntry();
}
void ThreadEntry() {
this.mtx.WaitOne();//等待该实例收到信号为止,类似enter
string name = Thread.CurrentThread.Name;
called += string.Format("{0}:{1}",name ,DateTime .Now .Millisecond);
Console.WriteLine(called);
this.mtx.ReleaseMutex(); //释放互斥体:类是exit
}
}
}
Mutex带有参数的构造函数
Mutex的构造函数接受一个bool类型的参数,指示创建Mutex的线程是否立即持有它;
相当于在mutex对象上调用waitone,其默认为false;
示例:
namespace Mutex有参数的构造函数
{
class Program
{
public System.Threading.Mutex mtx = new System.Threading.Mutex(true); //抢占:当前互斥体由主线程所有
private string called = "";
static void Main(string[] args)
{
Thread.CurrentThread.Name = "main ";
Program p = new Program();
Thread worker = new Thread(p.ThreadEntry);
worker.Name = "worker";
worker.Start();
Thread.Sleep(100); //让worker线程先执行:目的是为了让worker线程先执行;
p.ThreadEntry();
#region 防止主线程一直占有资源
//Thread.Sleep(100);
//p.MainJob();
#endregion
}
void ThreadEntry() {
this.mtx.WaitOne();//worker线程在进入此方法后,会一直阻塞在这里;因为当前互斥体由主线程所有。
string name = Thread.CurrentThread.Name;
called += string.Format("{0} {1}",name ,DateTime .Now.Millisecond);
Console.WriteLine(called);
this.mtx.ReleaseMutex();
}
#region 防止主线程一直占有资源
//void MainJob()
// {
// //在此线程中,至调用了ReleaseMutex方法,;
// //尽管对主线程使用了sleep方法,但是由于主线程持有互斥体,worker线程仍然会等待主线程先执行万mainjob方法才会继续执行
// string name = Thread.CurrentThread.Name;
// called += string.Format("{0} {1}", name, DateTime.Now.Millisecond);
// Console.WriteLine(called);
// this.mtx.ReleaseMutex();
// }
#endregion
}
}
Mutex创建Singleton应用程序
Mutex不仅提供跨线程的服务,还提供跨进程的服务。当在构造函数中为Mutex指定名称时,则会创建一个命名了的Mutex。
其他线程创建mutex时,如果指定的名称相同,则返回同一个互斥体,不论该线程位于哪个进程或者应用程序域中。
使用命名互斥体的一个例子是创建singleton应用程序,即只能打开一个实例的应用程序。
namespace Mutex创建singleton应用程序
{
class Program
{
static void Main(string[] args)
{
string asm = Assembly.GetExecutingAssembly().GetName().Name; //通过反射取值,获取到程序集的名称
Mutex mtx = new Mutex(false ,asm); //创建带有名称的互斥体
if (!mtx.WaitOne (TimeSpan.FromMilliseconds (100))) //该实例收到信号
{
Console .WriteLine ("{0} already running ",asm); //提示该实例已经在运行了
return ; //直接return
}
//主线程第一次进入
MainEntry(args);
mtx.ReleaseMutex();//释放互斥体
}
static void MainEntry(string[] args) {
Console.WriteLine("running~~~~~~~~~~~");
Console.ReadLine();
}
}
}