zoukankan      html  css  js  c++  java
  • 线程同步(AutoResetEvent与ManualResetEvent)

    前言


    在我们编写多线程程序时,会遇到这样一个问题:在一个线程处理的过程中,需要等待另一个线程处理的结果才能继续往下执行。比如:有两个线程,一个用来接收Socket数据,另一个用来处理Socket数据,而处理Socket数据的那个线程需要在接收到Socket数据后才能处理运行,就要等待接收线程接收数据。那么处理线程如何等待,接收线程又如何通知处理线程呢?

    其中一个比较好的方式就是使用AutoResetEvent/ManualResetEvent

     

    1. AutoResetEvent/ManualResetEvent介绍


    AutoResetEvent/ManualResetEvent是.Net给我们提供的用于线程间同步的对象。都有三个主要的函数:

    WaitOne: 用于阻塞线程,等待接收到继续运行信号

    Set:          用于发送同步信号,通知正在等待的线程继续运行

    Reset:      重置终止状态

    初始化构造函数ResetEvent(bool initialState),当initialState为true时,默认为终止状态(即阻塞无效);当initialState为false时,默认为非终止状态

    关于ResetEvent的终止状态与非终止状态,大家刚开始看的时候会感到难以理解,我举个很形象的例子,大家就会明白了。

    我们都有上班刷卡进大楼的经历,这里可以把ResetEvent看作是那个闸门,只有刷卡才能进。

    WaitOne就是等待刷卡,Set就是刷卡,而Reset则是关闭闸门,这样就知道,当初始化的时候,initialState为true时,意思就是说,默认闸门是开的;initialState为false时,默认闸门是关的

    所以,如果要进入大楼,步骤就应该是这样的(假设当前闸门是关着的),

    等待刷卡(WaitOne) ->刷卡(Set)->通信->关闭闸门(Reset)

     

    2. AutoResetEvent/ManualResetEvent的区别


    其实,这两个类的字面上的意思已经告诉了我们他们间的区别,Reset既然是关闭闸门,那也就是说,Auto是自动关闭闸门,Manual是手动关闭闸门。

    AutoResetEvent:刷卡通过后,闸门自动关闭,然后等待下一次刷卡

    ManualResetEvent:刷卡通过后,闸门不会自动关闭,如果不手动关闭(调用Reset方法),等待刷卡无效,人也就不用刷卡就能直接通过

    所以WaitOne是否有效,能不能阻塞线程取决于是否调用了Reset方法。

    而构造函数中initialState为true时,表示闸门默认第一次是打开的

     

    3. AutoResetEvent/ManualResetEvent使用示例


    接下来,我们用一个简单的示例来看一下这两个类的实际效果。 

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading;
    
    namespace ResetEventTest
    {
        class Program
        {
         //初始化时默认为非终止状态false static AutoResetEvent autoRE = new AutoResetEvent(false); static ManualResetEvent manualRE = new ManualResetEvent(false); static void Main(string[] args) { (new Thread(AutoMethod1)).Start(); (new Thread(AutoMethod2)).Start(); (new Thread(ManualMethod1)).Start(); (new Thread(ManualMethod2)).Start(); Console.ReadKey(); } static void AutoMethod1() { Console.WriteLine("wait print AutoMethod 1:"); autoRE.WaitOne(); Console.WriteLine("AutoMethod 1"); } static void AutoMethod2() { Console.WriteLine("wait print AutoMethod 2:"); autoRE.WaitOne(); Console.WriteLine("AutoMethod 2"); } static void ManualMethod1() { Console.WriteLine("wait print ManualMethod 1:"); manualRE.WaitOne(); Console.WriteLine("ManualMethod 1"); } static void ManualMethod2() { Console.WriteLine("wait print ManualMethod 2:"); manualRE.WaitOne(); Console.WriteLine("ManualMethod 2"); } } }

    分别对应AutoResetEvent和ManualResetEvent启动两个线程,全部进入等待,这时候输出为:

    我们发现线程全部阻塞,这说明初始化时false,就是设置为阻塞状态,那我们把初始化参数改为true试下

    static AutoResetEvent autoRE = new AutoResetEvent(true);
    static ManualResetEvent manualRE = new ManualResetEvent(true);
    

    结果如下:

    发现(注意输出顺序可能不同),Auto仅阻塞了一个,而Manual则两个都没有阻塞,全部输出了,实际上即是Auto放行一个后,立即自动调用了Reset方法,导致AutoMethod2在没有获取Set通行信号前无法继续运行;而Manual因为没有手动调用Reset方法,WaitOne形同虚设没有起任何作用。

    还使用之前的代码,在启动线程的时候添加Set代码,如下:

    static AutoResetEvent autoRE = new AutoResetEvent(false);
    static ManualResetEvent manualRE = new ManualResetEvent(false);
    
    static void Main(string[] args)
    {
        (new Thread(AutoMethod1)).Start();
        autoRE.Set();
        (new Thread(AutoMethod2)).Start();
    
        (new Thread(ManualMethod1)).Start();
        manualRE.Set();
        (new Thread(ManualMethod2)).Start();
    
        Console.ReadKey();
    }

    当AutoMethod1线程启动后,调用了Set方法,那么AutoMethod1线程就获得了继续运行的信号,这时候启动AutoMethod2线程,因为AutoMethod1线程运行后自动重置了状态,所以AutoMethod2就会阻塞;而ManualMethod1线程之后调用Set,因为没有手动调用Reset重置状态,那么ManualMethod2将不会阻塞,如下结果验证了我们的想法:

     

    如果想要ManualMethod2阻塞,那么只要在ManualMethod2中,获取到Set信号后,再调用Reset方法即可

    static void ManualMethod1()
    {
        Console.WriteLine("wait print ManualMethod 1:");
        manualRE.WaitOne();
        manualRE.Reset();
        Console.WriteLine("ManualMethod 1");
    }
    

    结果:

     

    4. 其他操作


    其实我们查看ResetEvent的继承关系会发现,实际上ResetEvent继承自抽象类WaitHandle,WaitHandle下的SignalAndWait,WaitAll与WaitAny方法提供了我们更多样的控制线程同步的方式,这个在以后会进一步探讨。

     

  • 相关阅读:
    hdu 5224 Tom and paper 水题
    2015 UESTC 搜索专题N题 韩爷的梦 hash
    2015 UESTC 搜索专题M题 Palindromic String 马拉车算法
    2015 UESTC 搜索专题K题 秋实大哥の恋爱物语 kmp
    2015 UESTC 搜索专题J题 全都是秋实大哥 kmp
    2015 UESTC 搜索专题F题 Eight Puzzle 爆搜
    2015 UESTC 搜索专题E题 吴队长征婚 爆搜
    2015 UESTC 搜索专题D题 基爷的中位数 二分
    2015 UESTC 搜索专题C题 基爷与加法等式 爆搜DFS
    2015 UESTC 搜索专题B题 邱老师降临小行星 记忆化搜索
  • 原文地址:https://www.cnblogs.com/houkui/p/4219008.html
Copyright © 2011-2022 走看看