多线程 -Synchronization Events and Wait Handles

 

多线程之间不能相互通信,为了达到这个目的。我们借助两个同步事件类:AutoResetEvent和ManualResetEvent。这两个类的功能是一样的,使用的唯一不同是前者调用Set()方法后,自动的调用Reset(),而后者不会。至于这里的Set()和ReSet() 的作用是什么,先放放,待会再说。因为想弄明白他们的作用之前我们必须要先明白另外的两个词:signaledunsignaled

 

1. signaledunsignaled

signaled :有信号的,表明收到了同步事件(AutoResetEvent和ManualResetEvent)的信号,通知被暂停(suspended )的线程可以继续执行了

unsignaled:没有信号的,同步事件没有收到信号,暂停的线程则继续等待。

我们可以把signal理解成中文“通知”,例如:

你和另外的一个人合作手工制作一辆组装自行车,你们分工,一个人做前轮,另外一个做后轮。很明显,你们没有必要一个人先做,另外一个人等着别人做好他再开始。所以你们一起开工(2个Thread同时start)。你做好了,并不能就立刻进行下一步组装,因为才一个轮子(一个Thread完成了),必须两个轮子都好了才能开始,所以你必须等你的同伴。反之亦然。

但是呢你们两个都在各自的家里做,都并不知道对方的进度状态 (因为线程之间并不能直接通过彼此传递信息来通信),可是你们又必须把两个轮子组合起来变成自行车。所以你们必须有中有效的机制来解决这个问题。于是就有了 AutoResetEvent和ManualResetEvent。

 

2. AutoResetEvent和ManualResetEvent :

 他们的作用就像个大喇叭,他们可以通过广播来播送信息,AutoResetEvent和ManualResetEvent则是通过调用 WaitOne(WaitAll(),waitany())和Set()两个方法来告诉所有拥有他们的线程发送信号:WaitOne()是对线程说,等你运行到这个地方,给我停下来,至于什么时候你可以继续前进,等候上面通知(什么时候调用了Set())。当ResetEvent调用了Set后,暂停的线程被唤醒便继续往下运行了。

 

ResetEvent  有两个状态,UnSignaled,signaled,在他们调用Wait 和Set的时候发生切换。说道状态切换,这里可以指出AutoResetEvent和Manuresetevent之间的唯一的一点区别了。

 AutoResetEvent autoEvent=new AutoResetEvent(false);

//false的话,初始状态就是阻止线程继续运行,当autoEvent.WaitOne()阻止线程的继续运行。一般都是设置阻止。

//如果是true, 就不会阻止了

   Thread t1 = new Thread(DoWork);
   t1.Start();

autoEvent.WaitOne();// autoEvent的状态由

  Console.WriteLine("Main thread is going on..."));

 

 

  static void DoWork()
        {
            Console.WriteLine(string.Format("  {0} worker thread started, now waiting on event...", Thread.CurrentThread.Name));
            autoEvent.Set();           
        }

 

 这里只有只有t1的线程完成后,通过Set()了,其他线程(这里是Main线程)才会继续运行

 

autoEnvet然后继续 Wait,再启动一个i额线程t2

 

 Thread t2 = new Thread(DoWork);

 

   t2.Start();

 

autoEvent.WaitOne();// autoEvent的状态由

这时候运行并不会出乎你的意外,正常运行。

但是如果 autoEvent 不是AutoResetEvent,而是一个ManuResetEvent,t2调用Dowork时候,你会发现Main线程不睬autoEvent.WaitOne()了,自己不等待直接先执行了。因为 autoEvent 这个时候的状态仍然是Signaled,即使你调用了waitOne(),它仍然不阻止,而是让任意多的线程一直是处于激活状态,除非你调用了Reset方法。

代码改成 

 autoEvent.Reset();//to reset initial state ,from signaled to unsignaled

  Thread t2 = new Thread(DoWork);

 

   t2.Start();

 

autoEvent.WaitOne();// autoEvent的状态由

 

 于是你可能会觉得ManualResetEvent多了一条代码,岂不是很麻烦吗?是有点,但是存在即是合理的。ManualResetEvent的好处是它Set一次后,可以激活任意多个Thread,不要像AutoResetEvent的每次都自动的给你Reset一下,尽管也很快,还是消耗一点性能,哪怕那只是一丁点,可是如果很多个线程呢?

 

3.Set 和Wait

Set倒是没有多少说的。Wait有点讲究,因为有些线程跑的块,有些跑的慢,那些特别快的线程有时候不愿意一直傻等那些慢线程,就像兔子真的是无法和乌龟共同赶路的一样。于是在event.wait的时候,我们可以设置个timeout时间

 int milliSeconds=1000;

 autoEvent.WaitOne(milliSeconds); 

 

这样,那些快线程等了1000毫秒后就可以闪人了。 


 

posted on 2011-12-29 16:41  鹤翔九天  阅读(252)  评论(0)    收藏  举报

导航