其实很早之前用过这个方法,只是很久没用,又生疏了。记录下来作为备忘。
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"); }
运行结果如下:
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;)得到的结果如下:
可以看到,回调首次不超时,而接下来在主线程结束之前,会有2次超时导致的调用。因此,这个方法也可用作计时器。微软的文档中,建议:
此方法返回的 RegisteredWaitHandle 使用完毕后,请调用其 RegisteredWaitHandle.Unregister 方法来释放对等待句柄的引用。 我们建议始终调用 RegisteredWaitHandle.Unregister 方法,即使将 executeOnlyOnce 指定为 true 也是如此。 如果调用 RegisteredWaitHandle.Unregister 方法而不是取决于注册的等待句柄的终结器,则垃圾回收的工作效率更高。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。