让一个线程不确定的等待一个内核对象进入可用状态,这对线程的内存资源来说是一种浪费。因此,线程池提供了一种方式,在一个内核对象变得可用的时候调用一个方法。这是通过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 RegisteredWaitHandleDemo 10 { 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传递null 21 5000, // Wait 5 seconds for the event to become true 等5秒事件变成true,就执行 EventOperation回调方法,
// 也就是每间隔5秒执行一次EventOperation 22 false); // Call EventOperation everytime the event is true 每次事件为true时,都调用 EventOperation 23 24 // Start our loop 25 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 event 31 } 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 or 38 // when 5 seconds have elapsed since the last callback/timeout 39 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 RegisteredWaitHandleDemo 10 { 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 AutoResetEvent 22 RegisteredWaitHandle rwh = ThreadPool.RegisterWaitForSingleObject( 23 are, // Wait on this AutoResetEvent 24 EventOperation, // When available, call the EventOperation method 25 null, // Pass null to EventOperation 26 5000, // Wait 5 seconds for the event to become true 27 false); // Call EventOperation everytime the event is true 28 29 // Start our loop 30 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 event 36 } 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 or 45 // when 5 seconds have elapsed since the last callback/timeout 46 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 书中的理解。。。。。欢迎各位大侠们拍砖指正错误之处。。。。。。。。。。