C# library 之 AutoResetEvent 与 ManualResetEvent

AutoResetEvent介绍

AutoResetEvent是.net线程简易同步方法中的一种。
AutoResetEvent 常常被用来在两个线程之间进行信号发送
两个线程共享相同的AutoResetEvent对象,线程可以通过调用AutoResetEvent对象的WaitOne()方法进入等待状态,然后另外一个线程通过调用AutoResetEvent对象的Set()方法取消等待的状态。

AutoResetEvent 如何工作

在内存中保持着一个bool值,如果bool值为False,则使线程阻塞,反之,如果bool值为True,则使线程退出阻塞。当我们创建AutoResetEvent对象的实例时,我们在函数构造中传递默认的bool值,以下是实例化AutoResetEvent的例子。

AutoResetEvent autoResetEvent = new AutoResetEvent(false);
WaitOne 方法

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

autoResetEvent.WaitOne();

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

static void ThreadMethod()
{
    while(!autoResetEvent.WaitOne(TimeSpan.FromSeconds(2)))
    {
        Console.WriteLine("Continue");
        Thread.Sleep(TimeSpan.FromSeconds(1));
    }
 
    Console.WriteLine("Thread got signal");
}

这里我们传递了2秒钟作为WaitOne方法的参数。在While循环中,autoResetEvent对象等待2秒,然后继续执行。当线程取得信号,WaitOne返回为True,然后退出循环,打印"Thread got signal"的消息。

Set 方法

AutoResetEvent Set方法发送信号到等待线程以继续其工作,以下是调用该方法的格式。

autoResetEvent.Set();

AutoResetEvent例子

下面的例子展示了如何使用AutoResetEvent来释放线程。在Main方法中,我们用Task Factory创建了一个线程,它调用了GetDataFromServer方法。调用该方法后,我们调用AutoResetEvent的WaitOne方法将主线程变为等待状态。在调用GetDataFromServer方法时,我们调用了AutoResetEvent对象的Set方法,它释放了主线程,并控制台打印输出dataFromServer方法返回的数据。

class Program
{
    static AutoResetEvent autoResetEvent = new AutoResetEvent(false);
    static string dataFromServer = "";
 
    static void Main(string[] args)
    {
        Task task = Task.Factory.StartNew(() =>
        {
            GetDataFromServer();
        });
 
        //Put the current thread into waiting state until it receives the signal
        autoResetEvent.WaitOne();
 
        //Thread got the signal
        Console.WriteLine(dataFromServer);
    }
 
    static void GetDataFromServer()
    {
        //Calling any webservice to get data
        Thread.Sleep(TimeSpan.FromSeconds(4));
        dataFromServer = "Webservice data";
        autoResetEvent.Set();
    }
}

AutoResetEvent和ManualResetEvent的区别

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

 
        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");
        }

我们对//_menuRestEvent.Reset()进行了注释,也就是说, _menuRestEvent.Set()后,线程的状态就是true状态的,程序运行的结果是"t1 step1 end"、“t2 step2 end”、在3秒之后弹出,然后隔1s “t1 step2 end”、"t2 step2 end"弹出。

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

R助手

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值