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则需要。
浙公网安备 33010602011771号