C#使用ManualResetEvent和AutoResetEvent处理线程通信

示例

两个线程交替输出“1 a 2 b 3 c 4 d 5 .....”

代码

    //利用ManualResetEvent和AutoResetEvent交替输出“1 a 2 b 3 c 4 d 5 .....”

    //ManualResetEvent和AutoResetEvent不同点:
    //AutoResetEvent 收到 Set 后 , 一次只能执行一个线程,其它线程继续 WaitOne 
    //ManualResetEvent 收到 Set 后,所有处理 WaitOne 状态线程均继续执行
    //AutoResetEvent.Set() = ManualResetEvent.Set() + ManualResetEvent.Reset();

    //在.Net多线程编程中,AutoResetEvent和ManualResetEvent这两个类经常用到, 他们的用法很类似,但也有区别。Set方法将信号置为发送状态,
    //Reset方法将信号置为不发送状态,WaitOne等待信号的发送。可以通过构造函数的参数值来决定其初始状态,若为true则非阻塞状态,为false为阻塞状态。
    //如果某个线程调用WaitOne方法,则当信号处于发送状态时,该线程会得到信号, 继续向下执行。其区别就在调用后,AutoResetEvent.WaitOne() 每次只允许一个线程进入, 
    //当某个线程得到信号后, AutoResetEvent会自动又将信号置为不发送状态, 则其他调用WaitOne的线程只有继续等待.
    //也就是说,AutoResetEvent一次只唤醒一个线程;而ManualResetEvent则可以唤醒多个线程,因为当某个线程调用了ManualResetEvent.Set() 方法后, 
    //其他调用WaitOne的线程获得信号得以继续执行, 而ManualResetEvent不会自动将信号置为不发送。也就是说,除非手工调用了ManualResetEvent.Reset() 方法, 
    //则ManualResetEvent将一直保持有信号状态, ManualResetEvent也就可以同时唤醒多个线程继续执行。

    //本质上AutoResetEvent.Set() 方法相当于ManualResetEvent.Set()+ManualResetEvent.Reset();
    //因此AutoResetEvent一次只能唤醒一个线程,其他线程还是堵塞
    class Program
    {
        private static List<ManualResetEvent> _listManual = new List<ManualResetEvent>();
        private static List<AutoResetEvent> _listAuto = new List<AutoResetEvent>();
        private static List<int> _listNumber = new List<int>() { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        private static List<char> _listLetter = new List<char>() { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j' };
        //private static List<char> _listUpperLetter = new List<char>() { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J' };
        static void Main(string[] args)
        {
            #region ManualResetEvent

            _listManual.Add(new ManualResetEvent(false));//用于控制_listNumber的信号灯
            _listManual.Add(new ManualResetEvent(false));//用于控制_listLetter的信号灯

            Task.Run(() =>
            {
                _listNumber.ForEach(c =>
                {
                    _listManual[0].WaitOne();
                    Console.WriteLine(c);
                    _listManual[0].Reset();
                    _listManual[1].Set();
                });
            });

            Task.Run(() =>
            {
                _listLetter.ForEach(c =>
                {
                    _listManual[1].WaitOne();
                    Console.WriteLine(c);
                    _listManual[0].Set();
                    _listManual[1].Reset();
                });
            });

            _listManual[0].Set();

            Console.ReadKey();

            #endregion

            #region AutoResetEvent

            _listAuto.Add(new AutoResetEvent(false));//用于控制_listNumber的信号灯
            _listAuto.Add(new AutoResetEvent(false));//用于控制_listLetter的信号灯

            Task.Run(() =>
            {
                _listNumber.ForEach(c =>
                {
                    _listAuto[0].WaitOne();
                    Console.WriteLine(c);
                    _listAuto[1].Set();
                    //不需要ReSet,因为AutoResetEvent在某个wait的线程得到信号后会自动变为ReSet,WaitOne每次只允许一个线程进入
                });
            });

            Task.Run(() =>
            {
                _listLetter.ForEach(c =>
                {
                    _listAuto[1].WaitOne();
                    Console.WriteLine(c);
                    _listAuto[0].Set();
                });
            });

            _listAuto[0].Set();

            Console.ReadKey();

            #endregion
        }
    }

    //Reset() //红灯
    //Set() //绿灯
    //WaitOne() // 等待信号

输出

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值