ThreadPool.RegisterWaitForSingleObject使用方法

简介:

其实很早之前用过这个方法,只是很久没用,又生疏了。记录下来作为备忘。

ThreadPool.RegisterWaitForSingleObject和ThreadPool.QueueUserWorkItem都是ThreadPool类中的静态方法。

ThreadPool.RegisterWaitForSingleObject 有4个重载函数,都大同小异。

这里只演示一种方法的使用

1
2
3
4
5
6
7
public  static  RegisteredWaitHandle RegisterWaitForSingleObject(
     WaitHandle waitObject,
     WaitOrTimerCallback callBack,
     Object state,
     int  millisecondsTimeOutInterval,
     bool  executeOnlyOnce
)

MSDN中的说明是:

注册一个等待 WaitHandle 的委托,并指定一个 32 位有符号整数来表示超时值(以毫秒为单位)。

说的比较模糊。我用自己的语言来叙述一下。

ThreadPool.RegisterWaitForSingleObject中必须传入一个WaitHandle,这个WaitHandle一旦接受到信号,或者没接收信号而超时了,则会调用WaitOrTimerCallback方法。这个超时时间由millisecondsTimeOutInterval设置的。如果超时时间设为-1,那么只要接受不到信号,那么一直WaitOrTimerCallback则一直不会运行。该方法不会阻塞线程,只是在线程池上开启一个线程来处理回调。

executeOnlyOnce的值为true/false。如果为 true,表示在调用了委托后,线程将不再在 waitObject 参数上等待;如果为 false,表示每次完成等待操作后都重置计时器,直到注销等待。

注意,WaitOrTimerCallback 委托 签名如下:

1
2
3
4
5
[ComVisibleAttribute( true )]
public  delegate  void  WaitOrTimerCallback(
Object state,
bool  timedOut
)

这个委托运行的时候,Object state参数就是RegisterWaitForSingleObject方法中传入的Object state,timedOut参数就是等待是否超时,如果RegisterWaitForSingleObject方法中的超时时间是10s,那么在10s后,WaitHandle还未收到信号,则为true,反之则反。

下面演示一段代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
static  void  Main( string [] args)
{
     Console.WriteLine(DateTime.Now.ToLongTimeString() +  " Main Thread start "  " threadID: "  + Thread.CurrentThread.GetHashCode());
     AutoResetEvent are =  new  AutoResetEvent( false );
     RegisteredWaitHandle waithandle = ThreadPool.RegisterWaitForSingleObject(are, (o, t) =>
     {
         string  s = ( string )o;
         Console.WriteLine(DateTime.Now.ToLongTimeString() +  " callback dosomething "  " threadID:"  + Thread.CurrentThread.GetHashCode());
         Console.WriteLine(DateTime.Now.ToLongTimeString() +  " TimeOut:"  + t.ToString());
     },  "state" , 2 * 1000,  true );
     Console.WriteLine(DateTime.Now.ToLongTimeString() +  " Main Thread did someting " );
     are.Set();
     Thread.Sleep(2000);
     Console.WriteLine(DateTime.Now.ToLongTimeString() +  " end" );
}

运行结果如下:

clipboard

RegisterWaitForSingleObject中的WaitOrTimerCallback方法是一个拉姆达表达式,超时时间为2秒。运行后可以看到主线程ID是1,WaitOrTimerCallback的线程ID是4,也证明了这个回调是在其他线程(线程池线程)中做的。 代码中Thread.Sleep(2000);如果不加入的话,可能主线程运行完毕,回调方法还未来得及运行。TimeOut为False。

如果在are.Set();  前面加上一句等待Thread.Sleep(3000);那么TimeOut为True,因为等3秒再给出信号已经超时了。

如果把RegisterWaitForSingleObject中的参数executeOnlyOnce设为false,那么方法中的回调会重复执行。(把主线程中的 Thread.Sleep改为5000;)得到的结果如下:

clipboard[1]

可以看到,回调首次不超时,而接下来在主线程结束之前,会有2次超时导致的调用。因此,这个方法也可用作计时器。微软的文档中,建议:

此方法返回的 RegisteredWaitHandle 使用完毕后,请调用其 RegisteredWaitHandle.Unregister 方法来释放对等待句柄的引用。 我们建议始终调用 RegisteredWaitHandle.Unregister 方法,即使将 executeOnlyOnce 指定为 true 也是如此。 如果调用 RegisteredWaitHandle.Unregister 方法而不是取决于注册的等待句柄的终结器,则垃圾回收的工作效率更高。














本文转自cnn23711151CTO博客,原文链接: http://blog.51cto.com/cnn237111/1538794,如需转载请自行联系原作者

相关文章
|
5月前
|
Java Linux API
Java多线程基础-4:详解Thread类及其基本用法 (一)
Java 中的 `Thread` 类是用来管理线程的,每个线程都是通过 `Thread` 类的对象来描述。
255 0
|
5月前
|
Java API 调度
【Java多线程】Thread类的基本用法
【Java多线程】Thread类的基本用法
36 0
|
10月前
|
Java 调度
【多线程】Thread类的基本用法
【多线程】Thread类的基本用法
【多线程】Thread类的基本用法
Thread 类的基本用法
比较推荐:使用 lambda 表达式创建线程的时候不用重写 run 方法。 不需要显式重写run方法的原因是因为线程的目标方法已经在Lambda表达式中定义了。Lambda表达式是一种用于创建匿名函数的语法糖,它可以将一个方法(或一段代码块)包装为一个函数对象。当您使用Lambda表达式创建线程时,Lambda表达式的内容会被视为线程执行的任务,这个任务会自动成为run方法的实现。
67 0
|
程序员 调度
多线程之Thread 类的基本用法
多线程之Thread 类的基本用法
|
Java
Future 任务机制和 FutureTask 的实现原理及使用方法
Future 任务机制和 FutureTask 的实现原理及使用方法
198 0
|
Java 程序员 Linux
Java多线程-线程的创建(Thread类的基本使用)
Java多线程-线程的创建(Thread类的基本使用)
142 0
Java多线程-线程的创建(Thread类的基本使用)
|
存储 Java Unix
Python线程池(thread pool)创建及使用+实例代码
Python线程池(thread pool)创建及使用+实例代码
1382 0
Python线程池(thread pool)创建及使用+实例代码