线程同步之AutoResetEvent和ManualResetEvent

AutoResetEvent和ManualResetEvent
表示一个线程同步事件

一:终止状态和非终止状态

首先说说线程的终止状态和非终止状态。AutoResetEvent和ManualResetEvent的构造函数中,都有bool变量来指明线程的终止状态和非终止状态。true表示终止状态(个人理解也就是可运行状态,根据理解应该是该线程的阻塞终止了),false表示非终止状态。

        AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
 
        private void BT_Temp_Click(object sender, RoutedEventArgs e)
        {
            Thread t1 = new Thread(this.Thread1Foo);
            t1.Start();
            Thread.Sleep(3000); //Thread.Sleep(Int32)是批当前进程挂起3000毫秒,与线程t1是一点关系也没有的。
            _autoResetEvent.Set();
        }
 
        void Thread1Foo()
        {
            _autoResetEvent.WaitOne();
            MessageBox.Show("t1 end");
        }

这段代码的执行结果,就是3秒钟过后,弹出“t1 end”。
而如果把:

   AutoResetEvent _autoResetEvent = new AutoResetEvent(false);

改为:

    AutoResetEvent _autoResetEvent = new AutoResetEvent(true);

则“t1 end”将会立刻弹出。
也就是说,在终止状态中,_autoResetEvent.WaitOne()是不会起到阻滞工作线程的作用的。(PS:ManualResetEvent也同样)

二:AutoResetEvent和ManualResetEvent的区别

AutoResetEvent 允许线程通过发信号互相通信。 通常,当线程需要独占访问资源时使用该类。

线程通过调用 AutoResetEvent 上的 WaitOne 来等待信号。 如果 AutoResetEvent 为非终止状态,则线程会被阻止,并等待当前控制资源的线程通过调用 Set来通知资源可用。

调用 Set 向 AutoResetEvent 发信号以释放等待线程。 AutoResetEvent 将保持终止状态,直到一个正在等待的线程被释放,然后自动返回非终止状态。 如果没有任何线程在等待,则状态将无限期地保持 为终止状态。如果当 AutoResetEvent 为终止状态时线程调用 WaitOne,则线程不会被阻止。 AutoResetEvent 将立即释放线程并返回到非终止状态。

    AutoResetEvent _autoResetEvent = new AutoResetEvent(false);
       private void BT_Temp_Click(object sender, RoutedEventArgs e)
       {
           Thread t1 = new Thread(this.Thread1Foo);
           t1.Start();
           Thread t2 = new Thread(this.Thread2Foo);
           t2.Start();
           Thread.Sleep(3000);
           _autoResetEvent.Set();
       }

       void Thread1Foo()
       {
           _autoResetEvent.WaitOne();
           MessageBox.Show("t1 end");
       }

       void Thread2Foo()
       {
           _autoResetEvent.WaitOne();
           MessageBox.Show("t2 end");
       }

该段代码运行的效果是,过3秒后,要么弹出“t1 end”,要么弹出“t2 end”,不会两个都弹出。也就是说,其中一个进行将会结束,而另一个进程永远不会结束。

代码段3:

        ManualResetEvent _menuRestEvent = new ManualResetEvent(false);
 
        private void BT_Temp_Click(object sender, RoutedEventArgs e)
        {
            Thread t1 = new Thread(this.Thread1Foo);
            t1.Start();
            Thread t2 = new Thread(this.Thread2Foo);
            t2.Start();
            Thread.Sleep(3000);
            _menuRestEvent.Set();
        }
 
        void Thread1Foo()
        {
            _menuRestEvent.WaitOne();
            MessageBox.Show("t1 end");
        }
 
        void Thread2Foo()
        {
            _menuRestEvent.WaitOne();
            MessageBox.Show("t2 end");
        }

该段代码运行的效果是,过3秒后,“t1 end”和“t2 end”,两个都被弹出。也就是说,两个进程都结束了。

这个特性就是说,AutoResetEvent只会给一个线程发送信号,而不会给多个线程发送信号。在我们需要同步多个线程的时候,就只能采用ManualResetEvent了。至于深层次的原因是,AutoResetEvent在set()之后,会将线程 状态自动置为false,而ManualResetEvent在Set()后,线程的状态就变为true了,必须手动ReSet()之后,才会重新将线程置为false。这也就是为什么他们的名字一个为Auto,一个为Manual的原因。为了更加充分的验证Manua lResetEvent的这点特性,我们再来看代码片段4

代码片段4:

    ManualResetEvent _menuRestEvent = new ManualResetEvent(false);
 
        private void BT_Temp_Click(object sender, RoutedEventArgs e)
        {
            Thread t1 = new Thread(this.Thread1Foo);
            t1.Start();
            Thread t2 = new Thread(this.Thread2Foo);
            t2.Start();
            Thread.Sleep(3000);
            _menuRestEvent.Set();
            //_menuRestEvent.Reset();           
        }
 
        void Thread1Foo()
        {
            _menuRestEvent.WaitOne();
            MessageBox.Show("t1 step1 end");
            //睡1S,用于等待主线程_menuRestEvent.Reset();
            Thread.Sleep(1000);
            _menuRestEvent.WaitOne();
            MessageBox.Show("t1 step2 end");
        }
 
        void Thread2Foo()
        {
            _menuRestEvent.WaitOne();
            MessageBox.Show("t2 step1 end");
            //睡1S,用于等待主线程_menuRestEvent.Reset();
            Thread.Sleep(1000);
            _menuRestEvent.WaitOne();
            MessageBox.Show("t2 step2 end");
        }

在代码片段4中,我们对//_menuRestEvent.Reset()进行了注释,也就是说, _menuRestEvent.Set()后,线程的状态就是true状态的,程序运行的结果是"t1 step1 end"、“t1 step2 end”、“t1 step2 end”、"t2 step2 end"在3秒之后全部弹出。

而如果我们将//_menuRestEvent.Reset()的注释去掉,会发现"t1 step2 end"和"t2 step2 end"永远不会弹出。除非我们在主线程中再次对_menuRestEvent进行Set()。

WaitOne 方法

该方法阻止当前线程继续执行,并使线程进入等待状态以获取其他线程发送的信号。WaitOne将当前线程置于一个休眠的线程状态。WaitOne方法收到信号后将返回True,否则将返回False。

WaitOne方法的第二个重载版本是等待指定的秒数。如果在指定的秒数后,没有收到任何信号,那么后续代码将继续执行。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值