ThreadPool 线程池
线程池是一个好东西。特别是在BS模式下的应用,对于多线程操作的有序和稳定实际展现的效果都还算让人满意的。
























ThreadPool的目标大抵都是为了减除线程的初始化开销,更好的实现并行处理。.NET类库中的ThreadPool是异步IO的基础,比如,在System.Net.Socket中,我们可以使用BeginAccept , EndAccept将Socket需要阻塞的操作放到系统的线程池中运行,而在执行结束以后通知主线程。
即使你没有在线程中显示的调用过ThreadPool的方法,只要你在写.NET程序,你就可能已经在使用线程池了,不信,打开一个.NET程序,在任务管理器中看看他的线程数,你会发现有N个线程运行中,即使你可能只使用了一个线程。如果你用了异步API的话,线程数目可能会让你觉得目瞪口呆。
ThreadPool的是一个静态类,它没有定义任何的构造方法,我们只能够使用它的静态方法,这是因为,这是因为ThreadPool是托管线程池,是由CLR管理的。
在我们的程序中也可以使用ThreadPool来进行一些比较耗时或者需要阻塞的操作。接下来我们将通过几个比较基本的例子开始我们的ThreadPool应用。
首先是我们如何将一个耗时的方法加入ThreadPool执行,这涉及到
ThreadPool.QueueUserWorkItem这个方法。
它的原型如下:
public static bool QueueUserWorkItem(System.Threading.WaitCallback callBack,object state);
public delegate void WaitCallback(object state);
下面是一个简单,但有效的WaitCallback定义,他展示了一种使用的方法:
static void testStatic(Object obj)
{ //获取线程外部参数,并转换成需要的类型
testObject tobj = obj as testObject;
tobj.calc();
}
对于其传递的参数 obj,主要是作为内部调用使用的,可以将它理解成LPARAM类似的结构,向线程传递更多的执行信息。
主线程中使用下面的语句将该操作加入线程池:
ThreadPool.QueueUserWorkItem(testStatic, new testObject());
后面一个对象是传递给委托实例(testStatic)的参数
主线程如果方法定义于不同的类中或者是实例方法的话,需要加上类型或者实例名称,
如:TestObj.testStatic或theObj.testStatic之类的
通常是将计算密集型的操作放在worker线程池中运行,而线程池的大小会根据当前的CPU使用量自动调整,通过下面两个方法,我们可以设置线程池的大小:
ThreadPool.SetMaxThreads(10, 200);ThreadPool.SetMinThreads(2, 40);
两个参数分别是WorkThread和IO thread的限制。 接下来我们来考虑如何运行一些重复的工作,如何使用ThreadPool来调度一些需要周期性运行的工作,.NET提供了System.Threading.Timer类实现这一个功能。使用涉及Timer和TimerCallback。后者也是一个委托,其声明如下:
public delegate void TimerCallback(object state);
显然,他的使用方法与上面WaitCallback的完全相同,我们可以简单的将上面的例子变成周期性运行的:
Timer tm = new Timer(new TimerCallback(testStatic),new testObject(),0,2000);后面的两个参数是启动的延迟时间和周期
Timer的线程分配机制与当前同时进行的其它Timer的时间复杂度有关系,当定义几个Timer同时工作的时候,如果每一个操作耗时较长,而且可能同时到期的话,线程池可能为每一个Timer操作定义不同的执行线程,而对于简单操作,有可能多个Timer被放在同一个线程中执行。
ThreadPool的另外一个很有用的场合是基于同步对象的调用,很多的场合下,我们会使用同步对象来调度多线程的运行,当某一个同步对象被通知的时候,等候的线程继续执行,而在此之前,这些线程将会阻塞。
常用的同步对象有以下几个:
Mutex , AutoResetEvent和ManualResetEvent。具体使用方法也比较简单,只是对于不同的同步对象,获取和释放的方法不同。
Mutex mtx = new Mutex(true);
ThreadPool.RegisterWaitForSingleObject(mtx,testMutex, mtx, 4000, true); mtx.ReleaseMutex();
是一个使用Mutex的例子,构造函数为true,则当前线程拥有Mutex。其它线程使用WaitOne函数等待该mutex。