.NET组件程序设计 第8章 多线程和并发管理 同步线程_可等待事件

3.可等待事件(EventWaitHandle)

EventWaitHandle派生自WaitHandle,用于跨线程通知事件。

EventWaitHandle有两种方式:手动重置(ManualReset)和自动重置(AutoReset)对应强类型子类ManualResetEvent和AutoResetEvent。

 

手动重置事件

public class EventDemo : IDisposable
{
    //创建手动重置事件对象
    private ManualResetEvent m_Event;

    //构造函数
    public EventDemo()
    {
        m_Event = new ManualResetEvent(false);

        //启动一个新线程
        Thread thread = new Thread(DoWork);
        thread.Start();
    }

    public void DoWork()
    {
        int counter = 0;
        while (true)
        {
            //阻塞当前线程,直到收到信号
            m_Event.WaitOne();

            counter++;
            Console.WriteLine("编号:" + counter);
        }
    }

    public void GoThread()
    {
        //设置句柄状态为:信号已发
        //一旦信号状态为已发,它就停留在已发状态,直到手动调用Reset()
        //信号已发,所有等待线程被解锁
        m_Event.Set();
        Console.WriteLine("开始!");
    }

    public void StopThread()
    {
        //设置句柄状态为:信号未发
        //阻塞线程
        m_Event.Reset();
        Console.WriteLine("中断!");
    }

    #region IDisposable 成员

    public void Dispose()
    {
        m_Event.Close();
    }

    #endregion
}

//调用
EventDemo ed = new EventDemo();

//在另一线程上调用ed的GoThread()等方法
ed.GoThread();
Thread.Sleep(10);
ed.StopThread();

ed.GoThread();
Thread.Sleep(10);
ed.StopThread();

 

自动重置事件

和手动重置事件基本相同,区别在:自动重置一旦调用Set()后,处于阻塞的线程开始运行,同时在这一刻,状态自动反转为型号未发(无需调用Rest())。如调用Set(),无线程等待,将继续保持信号已发状态。自动重置事件将Set()和Reset()调用结合到一个原子操作中

private AutoResetEvent m_Event;

/* 其他同上 */

//调用
//无需调用StopThread(),完成一原子操作状态自动变为未发信号
ed.GoThread();
Thread.Sleep(10);
ed.GoThread(); 

 

线程集结问题

线程相互等待,然后同时继续执行(并发完成)。

class Rendezvous
{
    //初始化信号为已发送状态(终止状态)
    AutoResetEvent m_First = new AutoResetEvent(true);

    AutoResetEvent m_Event1 = new AutoResetEvent(false);
    AutoResetEvent m_Event2 = new AutoResetEvent(false);

    //在某一点,每个线程调用该方法,
    //最先调用Wait()的线程,最先被阻塞
    //一旦第二个线程调用Wait(),两个线程都自动继续执行任务
    public void Wait()
    {
        //判断线程是否第一个调用
        //如果m_First收到信号(信号已发送状态),则为 true;否则为 false;
        //由于为AutoResetEvent实例,执行完原子操作后,会自动重置事件状态为信号未发状态,因此第二调用的线程返回值始终为false
        bool first = m_First.WaitOne(TimeSpan.Zero, false);

        if (first)
        {
            //给m_Event1发信号并等待m_Event2
            //SignalAndWait使发信号和等待为一元子操作进行,保证两线程,互相等待然后同时继续执行
            WaitHandle.SignalAndWait(m_Event1,m_Event2);
        }
        else
        {
            //给m_Event2发信号并等待m_Event1
            WaitHandle.SignalAndWait(m_Event2, m_Event1);
        }
    }

    public void Reset()
    {
        //重置m_First为信号已发送状态,用于再次集结两个线程
        m_First.Set();
    }
}

class Program
{
    static Rendezvous m_Rend = new Rendezvous();

    public static void ThreadMethod1()
    {
        m_Rend.Wait();

        Console.WriteLine(Thread.CurrentThread.Name);
    }

    public static void ThreadMethod2()
    {
        m_Rend.Wait();

        Console.WriteLine(Thread.CurrentThread.Name );
    }

    static void Main(string[] args)
    {
        //调用
        Thread threadA = new Thread(ThreadMethod1);
        threadA.Name = "threadA";
        threadA.Start();

        Thread threadB = new Thread(ThreadMethod2);
        threadB.Name = "threadB";
        threadB.Start();

        Console.Read();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值