ThreadPool.RegisterWaitForSingleObject使用方法

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

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

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

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

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 委托 签名如下:

[ComVisibleAttribute(true)]
public delegate void WaitOrTimerCallback(
Object state,
bool timedOut
)

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

下面演示一段代码。

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 方法而不是取决于注册的等待句柄的终结器,则垃圾回收的工作效率更高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值