关于AutoResetEvent和ManualResetEvent 全面总结

来源:互联网 发布:如何发淘宝店铺链接 编辑:程序博客网 时间:2024/06/03 20:01

两者都继承自EventWaitHandle,自然也就有点相通的地方了

简单来说,无论是AutoResetEvent还是ManualResetEvent,都是通过发出Signal信号来通知正在等待的线程的。

有人可能要问,为什么要用它们来做这些事情,

嗯, 是这样的, 在.Net的多线程环境中,资源的共享变得尤其重要,如果没有一个有效的方法来维护资源的原子状态,在抢占式的CPU环境中,所有的事情都会变得无法控制。AutoResetEvent和ManualResetEvent正是用来保证资源的原子性的一个手段的两个方面。

正如它们的名字一样, AutoResetEvent会在每次被Signal了之后自动(Automatically)转变为UnSignal,而ManualResetEvent则不然,无论是Signal还是UnSignal都需要人为的介入去改变它的状态。

在AutoResetEvent的构造函数中,有唯一的一个参数,initialState,Boolean类型,它用来初始化AutoResetEvent的Signal状态,True为Signal,False为UnSignal,这与ManualResetEvent的构造函数是一样的。

AutoResetEvent或ManualResetEvent都是通过Set()/Reset()两个方法来Signal/UnSignal信号,通过调用WaitOne方法来阻塞当前线程,当收到Signal后就继续往下执行。上面提到过,AutoResetEvent会自动把信号复位(自动调用Reset),而ManualResetEvent则需要人手复位,也就是说,AutoResetEvent每次只允许一条线程进入,其它所有需要访问该资源的线程都要排队等候,直到AutoResetEvent得到信号后,下一条线程开始工作,同时AutoResetEvent又会自动复位信号,让其他线程继续等候;而ManualResetEvent则每次可以唤醒多个线程,因为当ManualResetEvent得到信号后,其他调用WaitOne方法的线程都将得到信号得以继续往下执行,ManualResetEvent不会自动复位信号,换句话说,除非手动的调用了ManualResetEvent.Reset方法,否则ManualResetEvent一直保持有信号状态,这样就可以同时唤醒多条线程了

 

public partial class Form1 : Form    {        protected AutoResetEvent autoEvent;         protected ManualResetEvent manualEvent;          public Form1()         {             InitializeComponent();             autoEvent = new AutoResetEvent(true);            manualEvent = new ManualResetEvent(false);            Thread aThread = new Thread(new ParameterizedThreadStart(Foo));            aThread.Name = "aThread";            aThread.IsBackground = true;            aThread.Start();        }        private void Foo(object state)        {            MessageBox.Show("1");            autoEvent.WaitOne();           // manualEvent.WaitOne();            MessageBox.Show("2");            autoEvent.WaitOne();          //  manualEvent.WaitOne();            MessageBox.Show("3");        }        private void button1_Click(object sender, EventArgs e)        {            autoEvent.Set();           // manualEvent.Set();        }

作为一个示例,下面的DemoCode一开始就运行一条子线程,然后用AutoResetEvent/ManualResetEvent来控制MessageBox的输出流程。

如果在Foo和button1_Click里面用AutoResetEvent,一开始得到"1",然后每点击一次Button1得到"2"和"3"。

如果用ManualResetEvent,一开始得到"1",然后只需点击Button1一次,就可以得到"2"和"3"了

 

总结:

在C#多线程编程中,这两个类几乎是不可或缺的,他们的用法/声明都很类似,那么区别在哪里了

Set方法将信号置为发送状态 Reset方法将信号置为不发送状态 WaitOne等待信号的发送

其实,从名字就可以看出一点端倪  ,一个手动,一个自动,这个手动和自动实际指的是在Reset方法的处理上,如下面例子

public AutoResetEvent autoevent=new AutoResetEvent(true);

public ManualResetEvent manualevent=new ManualResetEvent(true);

默认信号都处于发送状态,

autoevent.WaitOne();

manualevent.WaitOne();

如果 某个线程调用上面该方法,则当信号处于发送状态时,该线程会得到信号,得以继续执行

差别就在调用后,autoevent.WaitOne()每次只允许一个线程进入,当某个线程得到信号(或有其他线程调用

了autoevent.Set()方法后)后,autoevent会自动又将信号置为不发送状态,则其他调用WaitOne的线程只有继续等待.也就是说,autoevent一次只唤醒一个线程

而manualevent则可以唤醒多个线程,因为当某个线程调用了set方法后,其他调用waitone的线程获得信号得以继续执行,而manualevent不会自动将信号置为不发送.也就是说,除非手工调用了manualevent.Reset().方法,则

manualevent将一直保持有信号状态,manualevent也就可以同时唤醒多个线程继续执行

 

这些内容是基于网络的各位前辈的内容能总结而成!

原创粉丝点击