让一个线程不确定的等待一个内核对象进入可用状态,这对线程的内存资源来说是一种浪费。因此,线程池提供了一种方式,在一个内核对象变得可用的时候调用一个方法。这是通过System.Threading.ThreadPool类的静态RegisterWaitForSingleObject方法来实现的。该方法有几个重载的版本,但这些版本全都是很相似。以下是一个较常用的重载版本的原型:
public static RegisteredWaitHandle RegisterWaitForSingleObject( WaitHandle waitObject, WaitOrTimerCallback callback, Object state, Int32 millsecondsTimeoutInterval, Boolean executeOnlyOnce);
参数说明:
waitObject:标识了你希望线程池等待的内核对象,由于这个参数的类型是抽象基类WaitHandle,所以可以指定从这个基类派生的任何类。具体的说,可以传递 对一个Semaphore、Mutex、AutoResetEvent或者ManualResetEvent对象的引用。
callback:标识了希望线程池线程调用的方法,这个回调方法必须匹配System.Threading.WaitOrTimerCallback委托:
public delegate void WaitOrTimerCallback(Object state,Boolean timedOut)
state:允许指定一些状态数据,线程池线程调用回调方法时,会将这个状态传给回调方法;如果没有特殊的状态数据需要传递,就传递null.
millsecondsTimeoutInterval:指定了线程池在等待内核对象收到信号时的超时时间。一般传递 Timeout.Infinite(-1),将超时时间设为“无限长”。通俗点就是每 间隔多少时间执行一次 callback方法。
executeOnlyOnce:为true时,线程池线程只执行回调方法一次,为false时,那么内核对象每次收到信号,线程此线程都会执行回调方法。
调用回调方法是,会向它传递状态数据和一个名为timedOut的Boolean值(通俗的说也就是在规定的时间millsecondsTimeoutInterval内,内核对象是否收到了信号),如果timedOut为false,方法知道他之所以被调用,是因为内核对象收到了信号。
如果timedOut为true,方法知道它之所以被调用,是因为内核对象在指定的时间内没收到信号。
注意:RegisterWaitForSingleObject方法返回的是对一个RegisteredWaitHandle对象的引用。这个对象标识了线程池线程正在它上面等待的内核对象。如果处于任何原因,你的应用程序向告诉线程池停止监视已登记的等待句柄,应用程序可以调用RegisteredWaitHandle的Unregister方法:
public Boolean Unregister(WaitHandle waitObject);
参数说明: waitObject参数指出,针对已登记等待句柄的、队列中的所有工作项都执行好之后,你想如何收到通知。
如果不想接收通知,应该为这个参数传递null.
如果传递的是对一个WaitHandle派生对象的有效引用,那么针对已登记的等待句柄的所有待决的工作项都执行完毕后,线程池线程就会向对象发出信号。
以下代码演示了如果在一个AutoResetEvent对象收到信号之后,让一个线程池线程调用一个方法:
1 // This example shows how a Mutex is used to synchronize access 2 // to a protected resource. Unlike Monitor, Mutex can be used with 3 // WaitHandle.WaitAll and WaitAny, and can be passed across 4 // AppDomain boundaries. 5 6 using System; 7 using System.Threading; 8 9 internal static class RegisteredWaitHandleDemo10 {11 public static void Main()12 {13 // Construct an AutoResetEvent (initially false)14 AutoResetEvent are = new AutoResetEvent(false);15 16 // Tell the thread pool to wait on the AutoResetEvent告诉线程池在AutoResetEvent上等待17 RegisteredWaitHandle rwh = ThreadPool.RegisterWaitForSingleObject(18 are, // Wait on this AutoResetEvent 在这个AutoResetEvent上等待19 EventOperation, // When available, call the EventOperation method 如果可用,就调用EventOperation方法20 null, // Pass null to EventOperation 向EventOperation传递null21 5000, // Wait 5 seconds for the event to become true 等5秒事件变成true,就执行 EventOperation回调方法, // 也就是每间隔5秒执行一次EventOperation22 false); // Call EventOperation everytime the event is true 每次事件为true时,都调用 EventOperation23 24 // Start our loop25 Char operation = (Char)0;26 while (operation != 'Q')27 {28 Console.WriteLine("S=Signal, Q=Quit?");29 operation = Char.ToUpper(Console.ReadKey(true).KeyChar);30 if (operation == 'S') are.Set(); // User want to set the event31 }32 33 // Tell the thread pool to stop waiting on the event,此处传递的是NULL,就不会向任何对象发送信号34 rwh.Unregister(null);35 }36 37 // This method is called whenever the event is true or38 // when 5 seconds have elapsed since the last callback/timeout39 private static void EventOperation(Object state, Boolean timedOut)40 {41 Console.WriteLine(timedOut ? "Timeout" : "Event became true");42 }43 }
以下的示例代码中 增加了取消登记时候发送信号的功能:
1 // This example shows how a Mutex is used to synchronize access 2 // to a protected resource. Unlike Monitor, Mutex can be used with 3 // WaitHandle.WaitAll and WaitAny, and can be passed across 4 // AppDomain boundaries. 5 6 using System; 7 using System.Threading; 8 9 internal static class RegisteredWaitHandleDemo10 {11 public static void Main()12 {13 // Construct an AutoResetEvent (initially false)14 AutoResetEvent are = new AutoResetEvent(false);15 16 AutoResetEvent arereult = new AutoResetEvent(false);17 18 System.Threading.Thread thr = new Thread(new ParameterizedThreadStart(TestUnregistered));19 thr.Start(arereult);20 21 // Tell the thread pool to wait on the AutoResetEvent22 RegisteredWaitHandle rwh = ThreadPool.RegisterWaitForSingleObject(23 are, // Wait on this AutoResetEvent24 EventOperation, // When available, call the EventOperation method25 null, // Pass null to EventOperation26 5000, // Wait 5 seconds for the event to become true27 false); // Call EventOperation everytime the event is true28 29 // Start our loop30 Char operation = (Char)0;31 while (operation != 'Q')32 {33 Console.WriteLine("S=Signal, Q=Quit?");34 operation = Char.ToUpper(Console.ReadKey(true).KeyChar);35 if (operation == 'S') are.Set(); // User want to set the event36 }37 38 // Tell the thread pool to stop waiting on the event 取消注册后,向arereult发送信号,TestUnregistered就会解除阻塞39 rwh.Unregister(arereult);40 41 Console.ReadLine();42 }43 44 // This method is called whenever the event is true or45 // when 5 seconds have elapsed since the last callback/timeout46 private static void EventOperation(Object state, Boolean timedOut)47 {48 Console.WriteLine(timedOut ? "Timeout" : "Event became true");49 }50 51 private static void TestUnregistered(object waithandle)52 {53 ((AutoResetEvent)waithandle).WaitOne();54 55 Console.WriteLine(" Test is TestUnregistered ");56 }57 58 }
以上的理解来源于 CLR 书中的理解。。。。。欢迎各位大侠们拍砖指正错误之处。。。。。。。。。。