zoukankan      html  css  js  c++  java
  • 理解多线程中的ManualResetEvent(C#)

    线程是程序中的控制流程的封装。你可能已经习惯于写单线程程序,也就是,程序在它们的代码中一次只在一条路中执行。如果你多弄几个线程的话,代码运行可能会更加“同步”。在一个有着多线程的典型进程中,零个或更多线程在同时运行。但是,在有着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();
            }
        }
    }
     
     
     
     
     
    另外一个例子:

    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 方法接显示每个斐波纳契的结果。

  • 相关阅读:
    尘埃里的路人乙
    SlidingMenu 插件的使用 二
    观察者模式
    Android SlidingMenu插件的使用
    Android4.2 的Http 多线程 网络传输
    Sliverlight界面研究1
    Sliverlight界面研究2
    图片切换效果(定时+编号)
    管理模型 RACI模型
    Enable NLA in XP
  • 原文地址:https://www.cnblogs.com/zxtceq/p/7779005.html
Copyright © 2011-2022 走看看