C#多线程处理之AutoResetEvent和ManualResetEvent

有时我们在具体开发中,需要使把程序设计成多线程的逻辑。

我们模拟这样一个场景:(C/S模式)

1.客户端向服务端发送测量命令。

2.服务端接受来自客户端的测量命令。

3.服务端进行测量工作。

4.服务端将测量结果,返回给客户端。

以上4步是一个完整的交互过程。当我们要求服务端同时相应有多个客户端的测试命令时,就需要使用到多线程设计:针对每一个客户端建立一个线程执行以上4步,和其他客户端的线程互不干扰。

多线程情况下,每个线程的执行顺序是并行的。但有时我们需要控制多个线程,使他们按特定的顺序执行,比如:当我们给上面的场景中的客服端加上‘优先级’的话。

这里我们讲下如何使用AutoResetEvent和ManualResetEvent来控制多个线程的执行。

1.简单的,我们创建3个线程,t1,t2,t3,依次打印出每个线程的ID,共打印10次。(现实中可能与不到这样的场景,但是这里用于演示如何控制多线程的)

方案a:AutoResetEvent实现:

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

namespace ConsoleApplication14
{
    class Program
    {
        static AutoResetEvent are1 = new AutoResetEvent(true);
        static AutoResetEvent are2 = new AutoResetEvent(false);
        static AutoResetEvent are3 = new AutoResetEvent(false);


        static void Main(string[] args)
        {              

            Thread t1 = new Thread(new ThreadStart(RunFun1));
            t1.Start();
            
            Thread t2 = new Thread(new ThreadStart(RunFun2));
            t2.Start();
            
            Thread t3 = new Thread(new ThreadStart(RunFun3));
            t3.Start(); 
           
            Console.Read();
        }

        static void RunFun1()
        {
            for (int i = 0; i < 10; i++)
            {
                are1.WaitOne();
                Console.WriteLine("The " + (i+1) + " times running:");
                Console.WriteLine("Thread t1 ID:" + Thread.CurrentThread.ManagedThreadId);              
                are2.Set();
            }

        }

        static void RunFun2()
        {
            for (int i = 0; i < 10; i++)
            {
                are2.WaitOne();
                Console.WriteLine("Thread t2 ID:" + Thread.CurrentThread.ManagedThreadId);               
                are3.Set();                
            }
        }

        static void RunFun3()
        {
            for (int i = 0; i < 10; i++)
            {
                are3.WaitOne();
                Console.WriteLine("Thread t3 ID:" + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine();
                are1.Set();
            }

        }

      
    }
}

 

方案b:ManualResetEvent实现:

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

namespace ConsoleApplication15
{
    class Program
    {
        static ManualResetEvent are1 = new ManualResetEvent(true);
        static ManualResetEvent are2 = new ManualResetEvent(false);
        static ManualResetEvent are3 = new ManualResetEvent(false);


        static void Main(string[] args)
        {

            Thread t1 = new Thread(new ThreadStart(RunFun1));
            t1.Start();

            Thread t2 = new Thread(new ThreadStart(RunFun2));
            t2.Start();

            Thread t3 = new Thread(new ThreadStart(RunFun3));
            t3.Start();

            Console.Read();
        }

        static void RunFun1()
        {
            for (int i = 0; i < 10; i++)
            {
                are1.WaitOne();
                Console.WriteLine("The " + (i + 1) + " times running:");
                Console.WriteLine("Thread t1 ID:" + Thread.CurrentThread.ManagedThreadId);
                ResetAll();
                are2.Set();
            }

        }

        static void RunFun2()
        {
            for (int i = 0; i < 10; i++)
            {
                are2.WaitOne();
                Console.WriteLine("Thread t2 ID:" + Thread.CurrentThread.ManagedThreadId);
                ResetAll();
                are3.Set();
            }
        }

        static void RunFun3()
        {
            for (int i = 0; i < 10; i++)
            {
                are3.WaitOne();
                Console.WriteLine("Thread t3 ID:" + Thread.CurrentThread.ManagedThreadId);
                Console.WriteLine();
                ResetAll();
                are1.Set();
            }

        }

        static void ResetAll()
        {
            are1.Reset();
            are2.Reset();
            are3.Reset();
        }


    }
}

 AutoResetEvent与ManualResetEvent的使用方式基本一样,区别在与前者被Set后,只能允许一个线程,且只能通过一次。后者则可以允许多个线程,通过多次,直到手动Reset才不允许线程通过。

 上面代码的基本思想就是:为每个线程分配一个属于自己的信号量,每个线程执行前都要请求自己的信号量,同时执行完以后,要释放另外一个线程的信号量(既是:唤醒另外线程)。

AuResetEvent变量每次被Set以后,WaitOne执行后,会自动恢复为非信号状态,不需要调用Reset。但是ManualResetEvent则需要。

 

posted @ 2013-04-03 21:57  MarkSun  阅读(467)  评论(0编辑  收藏  举报