在.Net多線(xiàn)程編程中,AutoResetEvent和ManualResetEvent這兩個(gè)類(lèi)經(jīng)常用到, 他們的用法很類(lèi)似,但也有區別。Set方法將信號置為發(fā)送狀態(tài),Reset方法將信號置為不發(fā)送狀態(tài),WaitOne等待信號的發(fā)送??梢酝ㄟ^(guò)構造函數的參數值來(lái)決定其初始狀態(tài),若為true則非阻塞狀態(tài),為false為阻塞狀態(tài)。如果某個(gè)線(xiàn)程調用WaitOne方法,則當信號處于發(fā)送狀態(tài)時(shí),該線(xiàn)程會(huì )得到信號, 繼續向下執行。其區別就在調用后,AutoResetEvent.WaitOne()每次只允許一個(gè)線(xiàn)程進(jìn)入,當某個(gè)線(xiàn)程得到信號后,AutoResetEvent會(huì )自動(dòng)又將信號置為不發(fā)送狀態(tài),則其他調用WaitOne的線(xiàn)程只有繼續等待.也就是說(shuō),AutoResetEvent一次只喚醒一個(gè)線(xiàn)程;而ManualResetEvent則可以喚醒多個(gè)線(xiàn)程,因為當某個(gè)線(xiàn)程調用了ManualResetEvent.Set()方法后,其他調用WaitOne的線(xiàn)程獲得信號得以繼續執行,而ManualResetEvent不會(huì )自動(dòng)將信號置為不發(fā)送。也就是說(shuō),除非手工調用了ManualResetEvent.Reset()方法,則ManualResetEvent將一直保持有信號狀態(tài),ManualResetEvent也就可以同時(shí)喚醒多個(gè)線(xiàn)程繼續執行。
ManualResetEvent類(lèi),AutoResetEvent類(lèi)
這兩個(gè)類(lèi)都是由EventWaitHandle類(lèi)派生出來(lái)的,所以功能和調用方法都很相似。
這兩個(gè)類(lèi)常用于阻斷某個(gè)線(xiàn)程的執行,然后在符合條件的情況下再恢復其執行。
舉個(gè)例子,你想送花給一個(gè)MM,托了一個(gè)送花的小伙子送了過(guò)去,而你希望當MM收到花之后就立即打個(gè)電話(huà)過(guò)去告訴她。
但問(wèn)題是你不知道花什么時(shí)候才送到MM的手里,打早了打遲了都不好,這時(shí)你可以使用ManualResetEvent對象幫忙。當委
托小伙子送花過(guò)去的時(shí)候,使用ManualResetEvent的WaitOne方法進(jìn)行等待。當小伙子把花送到MM的手中時(shí),再調用一下
ManualResetEvent的Set方法,你就可以準時(shí)地打電話(huà)過(guò)去了。
另外ManualResetEvent還有一個(gè)Reset方法,用來(lái)重新阻斷調用者執行的,情況就好比你委托了這個(gè)小伙子送花給N個(gè)MM,
而又想準時(shí)地給這N個(gè)MM打電話(huà)的情況一樣。
using System;
using System.Threading;
public class TestMain
{
private static ManualResetEvent ent = new ManualResetEvent(false);
public static void Main()
{
Boy sender = new Boy(ent);
Thread th = new Thread(new ThreadStart(sender.SendFlower));
th.Start();
ent.WaitOne(); //等待工作
Console.WriteLine("收到了吧,花是我送嘀:)");
Console.ReadLine();
}
}
public class Boy
{
ManualResetEvent ent;
public Boy(ManualResetEvent e)
{
ent = e;
}
public void SendFlower()
{
Console.WriteLine("正在送花的途中");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(200);
Console.Write("..");
}
Console.WriteLine("\r\n花已經(jīng)送到MM手中了,boss");
ent.Set(); //通知阻塞程序
}
}
而AutoResetEvent類(lèi)故名思意,就是在每次Set完之后自動(dòng)Reset。讓執行程序重新進(jìn)入阻塞狀態(tài)。
即AutoResetEvent.Set() 相當于 ManualResetEvent.Set() 之后又立即 ManualResetEvent.Reset(),
其他的就沒(méi)有什么不同的了。
舉個(gè)送花給N個(gè)MM的例子:
using System;
using System.Threading;
public class TestMain
{
private static AutoResetEvent ent = new AutoResetEvent(false);
public static void Main()
{
Boy sender = new Boy(ent);
for (int i = 0; i < 3; i++)
{
Thread th = new Thread(new ThreadStart(sender.SendFlower));
th.Start();
ent.WaitOne(); //等待工作
Console.WriteLine("收到了吧,花是我送嘀:)\r\n\r\n");
}
Console.ReadLine();
}
}
public class Boy
{
AutoResetEvent ent;
public Boy(AutoResetEvent e)
{
ent = e;
}
public void SendFlower()
{
Console.WriteLine("正在送花的途中");
for (int i = 0; i < 10; i++)
{
Thread.Sleep(200);
Console.Write("..");
}
Console.WriteLine("\r\n花已經(jīng)送到MM手中了,boss");
ent.Set(); //通知阻塞程序,這里的效果相當于 ManualResetEvent的Set()方法+Reset()方法
}
}
要注意的是ManualResetEvent和AutoResetEvent 的構造函數都有一個(gè)bool的參數,用這個(gè)參數可以指定初始情況下,同步對象的處于阻塞(設置為false)還是非阻塞(設置為true)的狀態(tài)。
另外WaitOne方法也可以帶兩個(gè)參數:
WaitOne (int millisecondsTimeout,bool exitContext)
millisecondsTimeout:等待的毫秒數,或為 Timeout.Infinite (-1),表示無(wú)限期等待。
exitContext:為 true,則等待之前先退出上下文的同步域(如果在同步上下文中),然后在稍后重新獲取它;否則為false。
就是說(shuō),等待是可以加上一個(gè)期限的,如果等待的同步對象一直都不Set()的話(huà),那么程序就會(huì )卡死,所以在WaitOne方法里面可以放置一個(gè)時(shí)間期限,單位是毫秒。