C# 线程手册 第五章 扩展多线程应用程序 剖析ThreadPool 类
2012-04-05 22:27 DanielWise 阅读(3610) 评论(2) 编辑 收藏 举报在这部分,我们将查看ThreadPool 类的多个方面并学习如何在我们的.NET 应用程序中使用ThreadPool 类的内容创建线程池。ThreadPool 类提供的线程可以用来做以下事情:
1. 处理工作组件
2. 处理异步I/O 调用
3. 处理定时器
4. 等待其他线程
下表给出了ThreadPool 类中的方法以及对应的功能。
上表中的QueueUserWorkItems() 和 RegisterWaitForSingleObject() 方法在线程池中起了非常重要的作用。我们将深入研究每个方法。现在看一下这两个方法的语法和一个用C# 写的小例子:
BindHandle() 方法绑定一个操作系统句柄到线程池上,通过这种方式可以调用BindIoCompletionCallback; BCL 中的几个类 - 比如Socket 和 FileStream – 内部使用这个方法来将它们的句柄绑定到一个由CLR 创建的线程池的I/O完全端口上去。客户端应用程序通常不需要直接调用这个方法,当BeginRead 或者 BeginReceive 方法被调用的时候系统会间接调用它们。
[Obsolete("ThreadPool.BindHandle(IntPtr) has been deprecated. Please use ThreadPool.BindHandle(SafeHandle) instead.", false), SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] public static bool BindHandle(IntPtr osHandle) { return BindIOCompletionCallbackNative(osHandle); }
osHandle 指向一个保存操作系统句柄的IntPtr 类型的值。函数的返回值是Boolean, true 表示已经绑定到句柄。如果调用方没有足够的权限的话,那么这个函数会抛出一个SecurityException.
GetAvailableThread() 方法获取在到达线程池队列最大限制之前仍然可以添加到线程池队列中的请求数量:
public static void GetAvailableThreads(out int workerThreads, out int completionPortThreads) { GetAvailableThreadsNative(out workerThreads, out completionPortThreads); }
workThreads 表示线程池中工作线程的数量而completionPortThreads 表示异步I/O 线程的数量。
GetMaxThreads() 方法获取一个线程池可以处理的最大并发请求数量。超过这个限制的任何请求都会被放入队列中直到线程池中的一些线程被释放以后它们才会被队列中取出执行:
public static void GetMaxThreads(out int workerThreads, out int completionPortThreads) { GetMaxThreadsNative(out workerThreads, out completionPortThreads); }
workThreads 表示线程池中的工作线程数量而completionPortThread表示异步I/O 线程的数量。
QueueUserWorkItem() 是一个用来将一个工作组件放入线程池中的重载方法。它可能被以下面的两种形式之一调用。第一种是这个方法将工作组件放入到线程池的队列中并调用与其关联的特定委托。这种情况下的语法如下:
[MethodImpl(MethodImplOptions.NoInlining)] public static bool QueueUserWorkItem(WaitCallback callBack) { StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller; return QueueUserWorkItemHelper(callBack, null, ref lookForMyCaller, true); }
这里callBack 引用一个在线程池中的线程关联到工作组件后调用的委托对象。返回值如果是true 表示方法成功,反之失败。
第二种情况是这个方法将特定工作组件放到线程池的队列中,并调用特定委托,当工作组件在线程池中执行时还要确定传递给委托的对象。这种情况下方法有如下语法:
[MethodImpl(MethodImplOptions.NoInlining)] public static bool QueueUserWorkItem(WaitCallback callBack, object state) { StackCrawlMark lookForMyCaller = StackCrawlMark.LookForMyCaller; return QueueUserWorkItemHelper(callBack, state, ref lookForMyCaller, true); }
callBack 引用一个当线程池中的线程执行工作组件以后调用的委托对象,state 引用当工作组件开始执行时传递给委托的状态对象。返回值是true 表示方法执行成功,反之失败。
RegisterWaitSingleObject() 也是一个重载方法。它注册一个等待WaitHandle 的委托。这个类封装了等待显式访问共享资源的操作系统对象。
这个方法采用以下四种形式之一。第一个形式,方法注册一个委托并等待WaitHandle 被超时(毫秒级, Int32)事件触发. 这种形式的重载方法有如下C# 语法:
[MethodImpl(MethodImplOptions.NoInlining)] public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, int millisecondsTimeOutInterval, bool executeOnlyOnce);
在上面的语法中,waitObject 引用WaitHandle对象,callBack 引用将要被调用的WaitOrTimerCallback 委托。state 参数引用传递给委托的对象。millisecondsTimeOutInterval 参数引用超时对象;如果值是0那么函数会测试对象的状态并立即返回,如果值是-1 函数会无限等待。executeOnlyOnce 参数表示线程在委托被调用之后是否继续等待。RegisterWaitHandle 参数封装了原生句柄。
如果millsecondsTimeOutInterval 参数小于-1 这个方法会抛出ArgumentOutOfRangeException.
第二种形式,方法与第一种方法的情况做的事情相同除了等待WaitHandle的时间参数类型为无符号Int32. 方法的重载形式如下:
[MethodImpl(MethodImplOptions.NoInlining)] public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, long millisecondsTimeOutInterval, bool executeOnlyOnce);
第三种形式,等待WaitHandle 的方法的超时时间由TimeSpan确定。方法的重载形式如下:
[MethodImpl(MethodImplOptions.NoInlining)] public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, TimeSpan timeout, bool executeOnlyOnce);
第四种形式,超时时间类型由一个无符号整数类型值确定,由于无符号整型类型不属于公共类型系统,所以这个方法不与CLS兼容:
[MethodImpl(MethodImplOptions.NoInlining), CLSCompliant(false)] public static RegisteredWaitHandle RegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, uint millisecondsTimeOutInterval, bool executeOnlyOnce);
UnsafeQueueUserWorkItem() 方法是QueueUserWorkItem() 方法的非安全版本。它不向工作线程传播调用堆栈所以它不是安全的,这意味着代码会丢失调用堆栈,这样的话获取安全权限就不可能了。它的语法如下:
public static bool UnsafeQueueUserWorkItem(WaitCallback callBack, object state);
UnsafeRegisterWaitForSingleObject() 方法是RegisterWaitForSingleObject() 方法的非安全版本,它有如下四种形式:
public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, int millisecondsTimeOutInterval, bool executeOnlyOnce);
public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, long millisecondsTimeOutInterval, bool executeOnlyOnce);
public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, TimeSpan timeout, bool executeOnlyOnce);
public static RegisteredWaitHandle UnsafeRegisterWaitForSingleObject(WaitHandle waitObject, WaitOrTimerCallback callBack, object state, uint millisecondsTimeOutInterval, bool executeOnlyOnce);
当从你不完全信任的代码执行工作组件时不应该使用这些不安全代码,一般不应该使用。
下一篇介绍 在C# 中使用线程池进行编程…
作者:DanielWise
出处:http://www.cnblogs.com/danielWise/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。