C#多线程编程(2):线程的同步
2010-09-30 21:09:36 来源:WEB开发网程序的执行效果如下:
WaitHandle
WaitHandle类是一个抽线类,有多个类直接或者间接继承自WaitHandle类,类图如下:
在 WaitHandle类中SignalAndWait、WaitAll、WaitAny及WaitOne这几个方法都有重载形式,其中除WaitOne之外都是静态的。WaitHandle方法常用作同步对象的基类。WaitHandle对象通知其他的线程它需要对资源排他性的访问,其他的线程必须等待,直到WaitHandle不再使用资源和等待句柄没有被使用。
WaitHandle方法有多个Wait的方法,这些方法的区别如下:
WaitAll:等待指定数组中的所有元素收到信号。
WaitAny:等待指定数组中的任一元素收到信号。
WaitOne:当在派生类中重写时,阻塞当前线程,直到当前的 WaitHandle 收到信号。
这些wait方法阻塞线程直到一个或者更多的同步对象收到信号。
下面的是一个MSDN中的例子,讲的是一个计算过程,最终的计算结果为第一项+第二项+第三项,在计算第一、二、三项时需要使用基数来进行计算。在代码中使用了线程池也就是ThreadPool来操作,这里面涉及到计算的顺序的先后问题,通过WaitHandle及其子类可以很好地解决这个问题。
代码如下:
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace StartThread
{
//下面的代码摘自MSDN,笔者做了中文代码注释
//周公
public class EventWaitHandleDemo
{
double baseNumber, firstTerm, secondTerm, thirdTerm;
AutoResetEvent[] autoEvents;
ManualResetEvent manualEvent;
//产生随机数的类.
Random random;
static void Main()
{
EventWaitHandleDemo ewhd = new EventWaitHandleDemo();
Console.WriteLine("Result = {0}.",
ewhd.Result(234).ToString());
Console.WriteLine("Result = {0}.",
ewhd.Result(55).ToString());
Console.ReadLine();
}
//构造函数
public EventWaitHandleDemo()
{
autoEvents = new AutoResetEvent[]
{
new AutoResetEvent(false),
new AutoResetEvent(false),
new AutoResetEvent(false)
};
manualEvent = new ManualResetEvent(false);
}
//计算基数
void CalculateBase(object stateInfo)
{
baseNumber = random.NextDouble();
//指示基数已经算好.
manualEvent.Set();
}
//计算第一项
void CalculateFirstTerm(object stateInfo)
{
//生成随机数
double preCalc = random.NextDouble();
//等待基数以便计算.
manualEvent.WaitOne();
//通过preCalc和baseNumber计算第一项.
firstTerm = preCalc * baseNumber *random.NextDouble();
//发出信号指示计算完成.
autoEvents[0].Set();
}
//计算第二项
void CalculateSecondTerm(object stateInfo)
{
double preCalc = random.NextDouble();
manualEvent.WaitOne();
secondTerm = preCalc * baseNumber *random.NextDouble();
autoEvents[1].Set();
}
//计算第三项
void CalculateThirdTerm(object stateInfo)
{
double preCalc = random.NextDouble();
manualEvent.WaitOne();
thirdTerm = preCalc * baseNumber *random.NextDouble();
autoEvents[2].Set();
}
//计算结果
public double Result(int seed)
{
random = new Random(seed);
//同时计算
ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateFirstTerm));
ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateSecondTerm));
ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateThirdTerm));
ThreadPool.QueueUserWorkItem(new WaitCallback(CalculateBase));
//等待所有的信号.
WaitHandle.WaitAll(autoEvents);
//重置信号,以便等待下一次计算.
manualEvent.Reset();
//返回计算结果
return firstTerm + secondTerm + thirdTerm;
}
}
}
程序的运行结果如下:
Result = 0.355650523270459.
Result = 0.125205692112756.
当然因为引入了随机数,所以每次计算结果并不相同,这里要讲述的是它们之间的控制。首先在 Result(int seed)方法中讲计算基数、第一项、第二项及第三项的方法放到线程池中,要计算第一二三项时首先要确定基数,这些方法通过 manualEvent.WaitOne()暂时停止执行,于是计算基数的方法首先执行,计算出基数之后通过manualEvent.Set()方法通知计算第一二三项的方法开始,在这些方法完成计算之后通过autoEvents数组中的AutoResetEvent元素的Set()方法发出信号,标识执行完毕。这样WaitHandle.WaitAll(autoEvents)这一步可以继续执行,从而得到执行结果。
在上面代码中的WaitHandle的其它子类限于篇幅不在这里一一举例讲解,它们在使用了多少有些相似之处(毕竟是一个爹、从一个抽象类继承下来的嘛)。
出处:http://zhoufoxcn.blog.51cto.com/792419/262608
更多精彩
赞助商链接