理解多线程中的ManualResetEvent(C#)

来源:互联网 发布:淘宝时尚的店铺 编辑:程序博客网 时间:2024/05/20 07:59
 转自:

http://www.cnblogs.com/BlueTzar/articles/864355.htmlManualResetEvent

线程是程序中的控制流程的封装。你可能已经习惯于写单线程程序,也就是,程序在它们的代码中一次只在一条路中执行。如果你多弄几个线程的话,代码运行可能会更加“同步”。在一个有着多线程的典型进程中,零个或更多线程在同时运行。但是,在有着N个CPU的机器上,一个线程只能在给定的时间上在一个CPU上运行,因为每个线程都是一个代码段,每个CPU一次只能运行一段代码。而看起来像是N个同时完成是线程间共享CPU时间片的效果。这个例子里,我们将创建另一个线程,我们将用两个线程演示多线程的工作方式,最后,我们实现两个线程(主线程与新线程)同步,在新线程工作前必须等待消息。建立线程前我们必须引入System.Threading命名空间。然后我需要知道的是,线程得为控制流程建立一个起点。起点是一个函数,可以使一个相同的调用或其它。
这里你可以看到在同一个类中定义的起点函数。
using System;
using System.Threading;
namespace ThreadingTester
{
    class ThreadClass
    {
        public static void trmain()
        {
            for (int x = 0; x < 10; x++)
            {
                Thread.Sleep(1000);
                Console.WriteLine(x);
            }
        }
        static void Main(string[] args)
        {
            Thread thrd1 = new Thread(new ThreadStart(trmain));
            thrd1.Start();
            for (int x = 0; x < 10; x++)
            {
                Thread.Sleep(900);
                Console.WriteLine("Main    :" + x);
            }
        }
    }
}
Thread.Sleep(n)方法把“this”线程置于n毫秒的休眠状态。你可以看看这个例子,在主函数我们定义了一个新的线程,其中它的起点是函数trmain(),我们然后包含了Start()方法开始执行。如果你运行这个例子,你就会了解线程间的切换(让CPU从运行一个线程转到另一个线程)让线程几乎同时运行,为了能看哪个线程运行更快我把主线程设置比新线程少100毫秒。
现在,在开始线程前,先给线程命名:
  Thread thrd1=new Thread(new ThreadStart(trmain));
  thrd1.Name="thread1";
  thrd1.Start();
  Thread tr = Thread.CurrentThread;
  Console.WriteLine(tr.Name);
在完成上面程序后,设想我们不想在一开始新线程就让它马上运行结束,也就是说,我们开启了一个新线程,让它运行,在某个特定的时间点,新线程暂停并等待从主线程(或其他线程)发来的消息。
我们可以这样定义:
  public static ManualResetEvent mre = new ManualResetEvent(false);
ManualResetEvent建立时是把false作为start的初始状态,这个类用于通知另一个线程,让它等待一个或多个线程。注意,为了通知或监听同一个线程,所有的其它线程都能访问那个类。
等待线程这样写:
  mre.WaitOne();
这将引起等待线程无限期的阻塞并等待类来通知。
发信号的线程应该这样:
  mre.Set();
这样类就会被通知,值变成true,等待线程就会停止等待。在通知事件发生后,我们就可以使用下面语句把线程置于基状态:
  mre.Reset();
现在让我们在程序执行一下:
using System;
using System.Threading;
namespace ThreadingTester
{
    class ThreadClass
    {
        public static ManualResetEvent mre = new ManualResetEvent(false);
        public static void trmain()
        {
            Thread tr = Thread.CurrentThread;
            Console.WriteLine("thread: waiting for an event");
            mre.WaitOne();
            Console.WriteLine("thread: got an event");
            for (int x = 0; x < 10; x++)
            {
                Thread.Sleep(1000);
                Console.WriteLine(tr.Name + ": " + x);
            }
        }
        static void Main(string[] args)
        {
            Thread thrd1 = new Thread(new ThreadStart(trmain));
            thrd1.Name = "thread1";
            thrd1.Start();
            for (int x = 0; x < 10; x++)
            {
                Thread.Sleep(900);
                Console.WriteLine("Main:" + x);
                if (5 == x) mre.Set();
            }
            while (thrd1.IsAlive)
            {
                Thread.Sleep(1000);
                Console.WriteLine("Main: waiting for thread to stop");
            }
            Console.ReadLine();
        }
    }
}
 
 
 
另可参考:   C#多线程学习(一) 多线程的相关概念
 
 
另外一个例子:

class Program
    {
        static void Main(string[] args)
        {
            const int taskNum = 10;
            FBNQC[] fbnqc = new FBNQC[taskNum];
            ManualResetEvent[] overEvents = new ManualResetEvent[taskNum];
            Random fbnqP = new Random();
            for (int i = 0; i < taskNum; i++)
            {
                overEvents[i] = new ManualResetEvent(false);
                fbnqc[i] = new FBNQC(fbnqP.Next(20, 40), overEvents[i]);
                ThreadPool.QueueUserWorkItem(fbnqc[i].CallBack , i);
            }
            WaitHandle.WaitAll(overEvents);
            for (int i = 0; i < taskNum; i++)
            {
                Console.WriteLine("Thread{0}'s parameter is {1},result is {2}!", i, fbnqc[i].pFBNQP, fbnqc[i].pFBNQR);
            }
            Console.ReadLine();

        }
    }

    class FBNQC
    {
        public int pFBNQP { get { return mFBNQP; } }
        public int pFBNQR { get { return mFBNQR; } }
        private int mFBNQP;
        private int mFBNQR;
        ManualResetEvent mOverEvents;
        public FBNQC (int oFBNQP,ManualResetEvent oOverEvents)
        {
            mFBNQP =oFBNQP ;
            mOverEvents =oOverEvents ;
        }

        public int  CalculateFBNQ (int oInt)
        {
            if (oInt <= 1) return oInt;
            return CalculateFBNQ(oInt - 1) + CalculateFBNQ(oInt- 2);
        }

        public void CallBack(object oObj)
        {
            int threadIndex=(int)oObj ;
            Console .WriteLine ("Thead{0} started....",threadIndex );
            mFBNQR = CalculateFBNQ(mFBNQP);
            Console.WriteLine("Thread{0} has finished!", threadIndex);
            mOverEvents.Set();
        }

注:

由于每个斐波纳契对象是给予一个半随机的值来进行计算,而且因为十个线程中的每一个线程将竞争处理机时间,没有办法提前知道要花多少时间才能计算出所有十个结果。那就是为什么在构造期间每个斐波纳契对象被传递一个ManualResetEvent类的实例。每个对象在完成计算之后发信号给提供了的事件对象,该事件对象允许主线程用WaitAll阻塞执行直到所有十个斐波纳契对象都计算完成,Main 方法接显示每个斐波纳契的结果。

 
上例摘自:http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80).aspx    并进行了一些修改.
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 苹果7来电铃声小怎么办 红米手机声音小怎么办 微信安装不上去怎么办 6s无法安装微信怎么办 苹果4微信版本低怎么办 新手机没有微信怎么办 新手机登陆微信怎么办 新号码被注册过怎么办 微信注册不了怎么办啊 苹果4铃声不响怎么办 苹果6黑屏没反应怎么办 苹果7卡机黑屏了怎么办 苹果7手机铃声小怎么办 支付宝发现套现怎么办 空调滴水管断了怎么办 地漏下水管断了怎么办 脸上长白色糠疹怎么办 腋下长白色的毛怎么办 饥荒电羊死光了怎么办 6s储存空间虚满怎么办 大胸下垂穿婚纱怎么办 美团签约成功后怎么办 拍婚纱照笑不出来怎么办 长得丑拍婚纱照怎么办 失恋了怎么办才能最快走出来 眼镜大了往下掉怎么办 眼镜带着往下掉怎么办 眼镜腿松了怎么办妙招 眼镜框大了总掉怎么办 吃不下饭恶心想吐怎么办 买到苹果翻新机怎么办 欠装修款不给怎么办 老板欠工资跑了怎么办 挖机老板欠工资怎么办 欠工程款耍赖不给怎么办 辞工后不给工资怎么办 工伤仲裁后不给怎么办 离职后不给工资怎么办 离职了不发工资怎么办 饭店欠工资不给怎么办 单位欠工资不给怎么办