c#多线程之mutex,semaphore,autoresetevent,manualResetevent

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的入参的区别:

  1. EventResetMode.AutoReset:当Set()被调用当前EventWaitHandle转入终止状态时,若有线程阻塞在当前EventWaitHandle上,那么在释放一个线程后EventWaitHandle就会自动重置(相当于自动调用Reset())再次转入非终止状态,剩余的原来阻塞的线程(如果有的话)还会继续阻塞。如果调用Set()后本没有线程阻塞,那么EventWaitHandle将保持“终止”状态直到一个线程尝试等待该事件,这个该线程不会被阻塞,此后EventWaitHandle才会自动重置并阻塞那之后的所有线程。   
  2. EventResetMode.ManualReset:当终止时,EventWaitHandle 释放所有等待的线程,并在手动重置前,即Reset()被调用前,一直保持终止状态。













你可能感兴趣的:(wpf)