线程同步:EventWaitHandle、ManualResetEvent,Mutex的使用

首先是EventWaitHandle表示一个线程同步事件。 提供了自动(EventResetMode.AutoReset)和手动(EventResetMode.ManualReset)两种方式,其主要区别是否自动将同步状态设置为非终止状态,以阻塞线程。

static void EventWaitHandleTest2(EventResetMode mode)
{
  EventWaitHandle r1 = new EventWaitHandle(false, mode);

  Thread t1 = new Thread(delegate()
    {
      while (true)
      {
        r1.WaitOne();

        Console.WriteLine("1");
        Thread.Sleep(1000);

        //r1.Reset();
        //r1.Set();
      }
    }
  );

  t1.Start();
  r1.Set();
}

当我们使用 EventWaitHandleTest2(EventResetMode.AutoReset); 调用该方法时,我们发现循环体在执行一次后并没有继续,线程被阻塞。而 EventWaitHandleTest2(EventResetMode.ManualReset); 调用时则不会阻塞,循环体无限执行下去。由此我们可以区别这两种状态的不同,自动方式会自动将同步状态设置为非终止,而手动则不会。自动状态时,我们删除 r1.Set(); 行的注释字符 (//),将状态重置为终止状态,则循环体自动进行下一轮执行;手动方式,我们将 r1.Reset(); 行的注释行删除,那么同步状态会被重置为非终止状态状态,那么线程体自然被阻塞,不会继续循环体的执行了。

.net Framework 2.0 的 AutoResetEvent 和 ManualResetEvent 继承自 EventWaitHandle,而不是 1.x 中继承自 WaitHandle。这两个类只是重写了构造方法而已。

public AutoResetEvent(bool initialState) : base(initialState, EventResetMode.AutoReset)
{
}

public ManualResetEvent(bool initialState) : base(initialState, EventResetMode.ManualReset)
{
}

接下来,我们另写一个例子。让两个线程交替执行。

using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Threading;

namespace ConsoleApplication1
{
  class Program
  {
    static void EventWaitHandleTest(EventResetMode mode)
    {
      EventWaitHandle r1 = new EventWaitHandle(false, mode);
      EventWaitHandle r2 = new EventWaitHandle(false, mode);

      Thread t1 = new Thread(delegate()
        {
          while (true)
          {
            r1.WaitOne();

            Console.WriteLine("1");
            Thread.Sleep(1000);

            if (mode == EventResetMode.ManualReset) r1.Reset();
            r2.Set();
          }
        }
      );

      Thread t2 = new Thread(delegate()
        {
          while (true)
          {
            r2.WaitOne();
            Console.WriteLine("2");

            if (mode == EventResetMode.ManualReset) r2.Reset();
            r1.Set();
          }
        }
      );

      t1.Start();
      t2.Start();

      r1.Set();
    }

    static void Main()
    {
      EventWaitHandleTest(EventResetMode.AutoReset);

      Console.WriteLine("Press any key to exit...");
      Console.ReadKey(true);
    }
  }
}

我们为什么要用2个同步对象呢?试想如果用一个的话在执行完 t1 的循环体 r1.Set(); 代码时,CPU 分配给 t1 的时间片断可能还没有超时,那么自然不会把执行权交给 t2,因为会继续执行 t1 的循环体代码,因此用 2 个则可以避免这种问题。

 

接下来是ManualResetEvent控制线程的唤醒和阻塞

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
 
namespace ManualResetEventDemo
{
    class MREDemo
    {
        private ManualResetEvent _mre;
 
        public MREDemo()
        {
            this._mre = new ManualResetEvent(true);
        }
 
        public void CreateThreads()
        {
            Thread t1 = new Thread(new ThreadStart(Run));
            t1.Start();
 
            Thread t2 = new Thread(new ThreadStart(Run));
            t2.Start();
        }
 
        public void Set()
        {
            this._mre.Set();
        }
 
        public void Reset()
        {
            this._mre.Reset();
        }
 
        private void Run()
        {
            string strThreadID = string.Empty;
            try
            {
                while (true)
                {
                    // 阻塞当前线程
                    this._mre.WaitOne();
 
                    strThreadID = Thread.CurrentThread.ManagedThreadId.ToString();
                    Console.WriteLine("Thread(" + strThreadID + ") is running...");
 
                    Thread.Sleep(5000);
                }
            }
            catch(Exception ex)
            {
                Console.WriteLine("线程(" + strThreadID + ")发生异常!错误描述:" + ex.Message.ToString());
            }
        }
 
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("****************************");
            Console.WriteLine("输入\"stop\"停止线程运行...");
            Console.WriteLine("输入\"run\"开启线程运行...");
            Console.WriteLine("****************************\r\n");
 
            MREDemo objMRE = new MREDemo();
            objMRE.CreateThreads();
 
            while (true)
            {
                string input = Console.ReadLine();
                if (input.Trim().ToLower() == "stop")
                {
                    Console.WriteLine("线程已停止运行...");
                    objMRE.Reset();
                }
                else if (input.Trim().ToLower() == "run")
                {
                    Console.WriteLine("线程开启运行...");
                    objMRE.Set();
                }
            }
             
        }
    }
}
 

 

接下来是Mutex(进程同步)Mutex

 

using System;
using System.Threading;
class Program
{
    static void Main(string[] args)
    {
        //需要打开两个对比【两个进程】
        Console.WindowWidth = 30; Console.BufferWidth = 30;
        Console.WindowHeight = 16; Console.BufferHeight = 16;

        Mutex mk = new Mutex(false, "test mutex");
        for (int i = 0; i < 1000; i++)
        {
            mk.WaitOne();
            for (int j = 0; j < 30; j++)
            {
                Console.Write(">");
                Thread.Sleep(100);
            }
            mk.ReleaseMutex();
            Thread.Sleep(500);
        }
    }
}

 

//多个互斥

using System;
using System.Threading;

class Program
{
    static void Main(string[] args)
    {
        //可以打开多个应用程序查看效果
        Console.WindowWidth = 30; Console.BufferWidth = 30;
        Console.WindowHeight = 16; Console.BufferHeight = 16;

        Mutex mk1 = new Mutex(false, "my mutex1");
        Mutex mk2 = new Mutex(false, "my mutex2");
        Mutex[] mks = new Mutex[] { mk1, mk2 };

        for (int i = 0; i < 1000; i++)
        {
            Mutex.WaitAll(mks);
            for (int j = 0; j < 30; j++)
            {
                Console.Write(">");
                Thread.Sleep(100);
            }

            mk1.ReleaseMutex();
            mk2.ReleaseMutex();
            Thread.Sleep(500);
        }

       //for循环修改为下面的试试

        for (int i = 0; i < 1000; i++)
        {
            int index = Mutex.WaitAny(mks);
            Console.Write("Index:" + index.ToString());
            for (int j = 0; j < 30; j++)
            {
                Console.Write(">");
                Thread.Sleep(50);
            }
            mks[index].ReleaseMutex();
            Thread.Sleep(300);
        }

    }
}

 

 

posted @ 2011-07-29 15:43  星释天狼  阅读(414)  评论(0)    收藏  举报