zoukankan      html  css  js  c++  java
  • C#多线程学习(六) 互斥对象

    如何控制好多个线程相互之间的联系,不产生冲突和重复,这需要用到互斥对象,即:System.Threading 命名空间中的 Mutex 类。

    我们可以把Mutex看作一个出租车,乘客看作线程。乘客首先等车,然后上车,最后下车。当一个乘客在车上时,其他乘客就只有等他下车以后才可以上 车。而线程与Mutex对象的关系也正是如此,线程使用Mutex.WaitOne()方法等待Mutex对象被释放,如果它等待的Mutex对象被释放 了,它就自动拥有这个对象,直到它调用Mutex.ReleaseMutex()方法释放这个对象,而在此期间,其他想要获取这个Mutex对象的线程都 只有等待。

    下面这个例子使用了Mutex对象来同步四个线程,主线程等待四个线程的结束,而这四个线程的运行又是与两个Mutex对象相关联的。

    其中还用到AutoResetEvent类的对象,可以把它理解为一个信号灯。这里用它的有信号状态来表示一个线程的结束。

    // AutoResetEvent.Set()方法设置它为有信号状态

    // AutoResetEvent.Reset()方法设置它为无信号状态

    Mutex 类的程序示例:

    View Code
    using System;
    using System.Threading;
    
    namespace ThreadExample
    {
        public class MutexSample
        {
          static Mutex gM1;
          static Mutex gM2;
          const int ITERS = 100;
          static AutoResetEvent Event1 = new AutoResetEvent(false);
          static AutoResetEvent Event2 = new AutoResetEvent(false);
          static AutoResetEvent Event3 = new AutoResetEvent(false);
          static AutoResetEvent Event4 = new AutoResetEvent(false);
    
          public static void Main(String[] args)
          {
                Console.WriteLine("Mutex Sample ");
                //创建一个Mutex对象,并且命名为MyMutex
                gM1 = new Mutex(true,"MyMutex");
                //创建一个未命名的Mutex 对象.
                gM2 = new Mutex(true);
                Console.WriteLine(" - Main Owns gM1 and gM2");
    
                AutoResetEvent[] evs = new AutoResetEvent[4];
                evs[0] = Event1; //为后面的线程t1,t2,t3,t4定义AutoResetEvent对象
                evs[1] = Event2; 
                evs[2] = Event3; 
                evs[3] = Event4; 
    
                MutexSample tm = new MutexSample( );
                Thread t1 = new Thread(new ThreadStart(tm.t1Start));
                Thread t2 = new Thread(new ThreadStart(tm.t2Start));
                Thread t3 = new Thread(new ThreadStart(tm.t3Start));
                Thread t4 = new Thread(new ThreadStart(tm.t4Start));
                t1.Start( );// 使用Mutex.WaitAll()方法等待一个Mutex数组中的对象全部被释放
                t2.Start( );// 使用Mutex.WaitOne()方法等待gM1的释放
                t3.Start( );// 使用Mutex.WaitAny()方法等待一个Mutex数组中任意一个对象被释放
                t4.Start( );// 使用Mutex.WaitOne()方法等待gM2的释放
    
                Thread.Sleep(2000);
                Console.WriteLine(" - Main releases gM1");
                gM1.ReleaseMutex( ); //线程t2,t3结束条件满足
    
                Thread.Sleep(1000);
                Console.WriteLine(" - Main releases gM2");
                gM2.ReleaseMutex( ); //线程t1,t4结束条件满足
    
                //等待所有四个线程结束
                WaitHandle.WaitAll(evs); 
                Console.WriteLine(" Mutex Sample");
                Console.ReadLine();
          }
    
          public void t1Start( )
          {
                Console.WriteLine("t1Start started, Mutex.WaitAll(Mutex[])");
                Mutex[] gMs = new Mutex[2];
                gMs[0] = gM1;//创建一个Mutex数组作为Mutex.WaitAll()方法的参数
                gMs[1] = gM2;
                Mutex.WaitAll(gMs);//等待gM1和gM2都被释放
                Thread.Sleep(2000);
                Console.WriteLine("t1Start finished, Mutex.WaitAll(Mutex[]) satisfied");
                Event1.Set( ); //线程结束,将Event1设置为有信号状态
          }
          public void t2Start( )
          {
                Console.WriteLine("t2Start started, gM1.WaitOne( )");
                gM1.WaitOne( );//等待gM1的释放
                Console.WriteLine("t2Start finished, gM1.WaitOne( ) satisfied");
                Event2.Set( );//线程结束,将Event2设置为有信号状态
          }
          public void t3Start( )
          {
                Console.WriteLine("t3Start started, Mutex.WaitAny(Mutex[])");
                Mutex[] gMs = new Mutex[2];
                gMs[0] = gM1;//创建一个Mutex数组作为Mutex.WaitAny()方法的参数
                gMs[1] = gM2;
                Mutex.WaitAny(gMs);//等待数组中任意一个Mutex对象被释放
                Console.WriteLine("t3Start finished, Mutex.WaitAny(Mutex[])");
                Event3.Set( );//线程结束,将Event3设置为有信号状态
          }
          public void t4Start( )
          {
                Console.WriteLine("t4Start started, gM2.WaitOne( )");
                gM2.WaitOne( );//等待gM2被释放
                Console.WriteLine("t4Start finished, gM2.WaitOne( )");
                Event4.Set( );//线程结束,将Event4设置为有信号状态
          }
        }
    }

    程序的输出结果:

    输出结果
    Mutex Sample 
     - Main Owns gM1 and gM2
    t1Start started, Mutex.WaitAll(Mutex[])
    t2Start started, gM1.WaitOne( )
    t3Start started, Mutex.WaitAny(Mutex[])
    t4Start started, gM2.WaitOne( )
     - Main releases gM1
    t2Start finished, gM1.WaitOne( ) satisfied
    t3Start finished, Mutex.WaitAny(Mutex[])
     - Main releases gM2
    t1Start finished, Mutex.WaitAll(Mutex[]) satisfied
    t4Start finished, gM2.WaitOne( )
     Mutex Sample

    从执行结果可以很清楚地看到,线程t2,t3的运行是以gM1的释放为条件的,而t4在gM2释放后开始执行,t1则在gM1和gM2都被释放了之后才执 行。Main()函数最后,使用WaitHandle等待所有的AutoResetEvent对象的信号,这些对象的信号代表相应线程的结束。

    --------------------------------------

    欢迎您,进入 我系程序猿 的cnBlog博客。

    你不能改变你的过去,但你可以让你的未来变得更美好。一旦时间浪费了,生命就浪费了。

    You cannot improve your past, but you can improve your future. Once time is wasted, life is wasted.

    --------------------------------------

    分享到QQ空间  

  • 相关阅读:
    POJ 1141 括号匹配 DP
    881. Boats to Save People
    870. Advantage Shuffle
    874. Walking Robot Simulation
    文件操作
    861. Score After Flipping Matrix
    860. Lemonade Change
    842. Split Array into Fibonacci Sequence
    765. Couples Holding Hands
    763. Partition Labels
  • 原文地址:https://www.cnblogs.com/jqmtony/p/2911020.html
Copyright © 2011-2022 走看看