mutex,semaphore,autoresetevent,manualResetevent四个类都继承自waitHandle类,其中autoresetevent,manualResetevent都继承自EventWaitHandle,且EventWaitHandle的构造函数提供了一个入参EventResetMode来设置为manualreset还是autoreset,故我们只需查看mutex,semaphore,eventwaithandle的区别即可。
观察这三个类的函数,发现大部分函数都是相同的,不同的就是
mutex类包含 public void ReleaseMutex();
semaphore包含 public int Release(); public int Release(int releaseCount);
EventWaitHandle包含 public bool Reset(); public bool Set();
再来看三个类的定义
mutex:A synchronization primitive that can also be used for interprocess synchronization. 一个原语同步,也可用于进程间同步
semaphore:Limits the number of threads that can access a resource or pool of resources concurrently. 限制访问资源的线程个数
EventWaitHandle:Represents a thread synchronization event. 线程的同步信号
1.mutex,互斥锁,一般用于资源竞争时对临界区的保护:
实例:
class Program
{
static Mutex myMutex; //互斥锁
static void UserResource()
{
myMutex.WaitOne(); //多个线程竞争,等待锁
Console.WriteLine("get resource"+Thread.CurrentThread.Name);
Thread.Sleep(3000);
myMutex.ReleaseMutex();
}
static void Main(string[] args)
{
myMutex = new Mutex();
int threadNum = 5;
Thread[] threads = new Thread[threadNum];
for (int i = 0; i < threadNum; i++)
{
threads[i] = new Thread(new ThreadStart(UserResource));
threads[i].Name = "threads" + i.ToString();
threads[i].Start();
}
Console.Read();
}
}输出结果,每隔三秒输出一次
以上通过mutex只是控制了各个线程的资源互斥,如果要想使各个线程的执行时有序的,可以在执行前不断的判断各个线程的顺序执行条件。
要想使mutex实现进程间的资源互斥,需要使用“命名mutex”,将如上代码修改为 myMutex = new Mutex(false,"myMutex");即可。
2.semaphore实例:
class Program
{
static Semaphore s;
static void UserResource()
{
s.WaitOne();
Console.WriteLine("get resource" + Thread.CurrentThread.Name);
Thread.Sleep(3000);
s.Release();
}
static void Main(string[] args)
{
s = new Semaphore(2, 5); //初始num为2,最大num为5
int threadNum = 5;
Thread[] threads = new Thread[threadNum];
for (int i = 0; i < threadNum; i++)
{
threads[i] = new Thread(new ThreadStart(UserResource));
threads[i].Name = "threads" + i.ToString();
threads[i].Start();
}
Thread.Sleep(10000);
for (int i = 0; i < threadNum; i++)
{
threads[i].Abort();
}
Console.WriteLine("abort");
Console.Read();
}
}
输出的结果是线程两个两个的进入临界区,如果在执行过程中想要调整信号量的初始大小,则可以使用int Release(int releaseCount)函数,注意不要使初始num大于maxnum,否则会出异常。
3.EventWaitHandle
EventWaitHandle和Mutex的区别在于Mutex使用waitone是企图占有锁,一旦获取,则资源只能归这个线程使用,而EventWaitHandle使用waitone则是在等待通知,一旦信号被set了,则可以使用该资源了,如果多个线程同时在等待通知,那么一旦信号来了,多个线程同时执行,没有起到互斥的作用,所以EventWaitHandle一般用在线程间的通信上。
实例,让多个线程顺序执行
class Program
{
static EventWaitHandle[] ewhs;
static void UserResource(object o)
{
int i = (int)o;
ewhs[i].WaitOne();
Console.WriteLine("get resource" + Thread.CurrentThread.Name);
Thread.Sleep(2000);
if (i + 1 < ewhs.Length)
{
ewhs[i+1].Set(); //开启下一个线程的信号
}
}
static void Main(string[] args)
{
int threadNum = 5;
ewhs = new EventWaitHandle[threadNum]; //信号灯数组,用于分别控制多个线程的执行
Thread[] threads = new Thread[threadNum];
for (int i = 0; i < threadNum; i++)
{
string name = "ewh" + i.ToString();
EventWaitHandle ewh = new EventWaitHandle(false, EventResetMode.AutoReset,name); //默认信号灯都为没有信号
ewhs[i] = ewh;
threads[i] = new Thread(new ParameterizedThreadStart(UserResource));
threads[i].Name = "threads" + i.ToString();
threads[i].Start(i);
}
ewhs[0].Set(); //开启第一个线程的信号,使其开始执行,其他线程阻塞。
Console.Read();
}
}
输出结果为从第一个线程开始顺序执行。
最后来看一下autoresetevent和manualResetevent的区别,也就是EventWaitHandle的入参的区别: