WEB开发网
开发学院软件开发C语言 C#多线程编程(2):线程的同步 阅读

C#多线程编程(2):线程的同步

 2010-09-30 21:09:36 来源:WEB开发网   
核心提示: 程序的执行效果如下:WaitHandleWaitHandle类是一个抽线类,有多个类直接或者间接继承自WaitHandle类,C#多线程编程(2):线程的同步(8),类图如下:在 WaitHandle类中SignalAndWait、WaitAll、WaitAny及WaitOne这几个方法都有重载

程序的执行效果如下:

C#多线程编程(2):线程的同步

WaitHandle

WaitHandle类是一个抽线类,有多个类直接或者间接继承自WaitHandle类,类图如下:

C#多线程编程(2):线程的同步

在 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

上一页  3 4 5 6 7 8 

Tags:线程 编程 线程

编辑录入:爽爽 [复制链接] [打 印]
赞助商链接