zoukankan      html  css  js  c++  java
  • ManualResetEvent用法

    转之:http://blog.tom.com/blog/read.php?bloggerid=313638&blogid=13505
    Thread and Sync In C# (C#中的线程与同步)
    别相信别人告诉你的所有的事。其实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");
    }
    }
    }
    }

    ManualResetEvent就像一个信号灯,可以利用它的信号,控制当前线程是挂起状态还是运行状态。
            它有几个常用的方法:Reset(),Set(),WaitOne();
            初始化该对象时,可以指定其默认的状态(有信号/无信号);
            在初始化以后,该对象将保持原来的状态不变,直到它的Reset()或者Set()方法被调用;
            Reset()方法将其设置为无信号状态,Set()方法将其设置为有信号状态;
            WaitOne()方法在无信号状态下,可以使当前线程挂起;注意这里说的是当前线程;
            直到调用了Set()方法,该线程才被激活。

            在多线程的代码里,可以使用一个ManualResetEvent对象来控制线程所有线程;
            只要在调用WaitOne()方法前,调用Reset()方法,因为WaitOne()控制的是当前线程;
            但是这样做,ManualResetEvent对象的管理逻辑会变得复杂;
            所以这里建议一条线程一个ManualResetEvent对象。

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Threading;

    namespace ConsoleThread
    {
    class ThreadClass
    {
    public void threadFun()
    {
                Thread.Sleep(1000);
                Console.WriteLine("ThreadClass.threadFun 1");

    //激活被挂起的线程
                Program.allDone.Set();

                Console.WriteLine("ThreadClass.threadFun 2");

    //设置为无信号,如果注释这条语句,
    //下面的WaitOne()方法就不起做用了
                Program.allDone.Reset();

    //使当前线程挂起
                Program.allDone.WaitOne();

                Console.WriteLine("ThreadClass.threadFun 3");

            }

        };



    class Program
    {
    public static ManualResetEvent allDone = new ManualResetEvent(false);
    static void Main(string[] args)
    {
                Console.WriteLine("Thread Start/Stop/Join Sample");
                ThreadClass ThreadC = new ThreadClass();
                Thread thread = new Thread(new ThreadStart(ThreadC.threadFun));
                thread.Start();

    //挂起当前线程
                allDone.WaitOne();

                Console.WriteLine("Main 1");

    //因为ThreadClass.threadFun方法里调用了Reset()
    //所以这里的WaitOne()方法会使主线程也挂起
    //allDone.WaitOne();

    //使主线程挂起1秒钟,
    //为了ThreadClass.threadFun方法里的Program.allDone.WaitOne()方法
    //运行时间在Main()方法的allDone.Set()方法前面
                Thread.Sleep(5000);

    //设置为有信号
    //如果没有这条语句,ThreadClass.threadFun方法里最后一条语句就不会运行
                allDone.Set();
                Console.WriteLine("Main 2");
            }
        }
    }

    魔兽就是毒瘤,大家千万不要玩。
  • 相关阅读:
    解决在PDF文档中复制代码报错问题
    JAVA高级复习泛型
    SpringBoot高级监听原理
    SpringBoot整合其它框架整合Junit
    SpringBoot高级监控
    JAVA基础复习异常处理
    SpringBoot 整合 webservice 示例
    关于ScrollView的子View无法布满屏幕的问题
    Android开发中头疼的R文件问题
    博客园美化[SimpleMemory主题+tctip插件]
  • 原文地址:https://www.cnblogs.com/tracy/p/1860543.html
Copyright © 2011-2022 走看看