1. 引言
近来在研究C#多线程编程碰到了线程池的概念。不懂,我搜,于是在MSDN和CSDN上寻寻觅觅一番终于搞明白,“缘”来如此,安装本人理解修改后写下这篇文章,希望对后来者有所帮助。
2. 线程池的概念
可以使用线程池来根据应用程序的需要更为有效地利用多个线程。许多应用程序使用多个线程,但这些线程经常在休眠状态中耗费大量的时间来等待事件发生,编程者手动管理多个线程也是一件比较麻烦的事情。事实上,使用线程池就是为应用程序提供一个由系统管理的辅助线程池,从而使您可以集中精力于应用程序任务而不是线程管理。
实际上,如果要执行一些需要多个线程的较短任务,则使用 ThreadPool 类是利用多个线程的最方便且最好的方法。使用线程池能够优化这些任务的执行过程,从而提高吞吐量,它不仅能够使系统针对此进程优化该执行过程,而且还能够使系统针对计算机上的其他进程优化该执行过程,即使您的应用程序对这些进程一无所知,系统也能做到这一点。使用线程池使系统能够在考虑到计算机上的所有当前进程后对线程时间片进行优化。
.NET Framework 出于以下几个目的使用线程池:异步调用、System.Net 套接字连接、异步 I/O 完成以及计时器与注册的等待操作等等。
每个进程只有一个ThreadPool对象。线程池在您第一次调用 ThreadPool.QueueUserWorkItem 时创建,或者在一个计时器或注册的等待操作将一个回调方法排入队列时创建。一个线程监视所有已排队到线程池中的任务。当某项任务完成后,线程池中的线程将执行相应的回调方法。在对一个工作项进行排队之后将无法取消它。
通过调用System.Threading.ThreadPool.QueueUserWorkItem(WaitCallback)来使用线程池,WaitCallback是要添加到队列中的方法。也可以通过使用System.Threading.ThreadPool.RegisterWaitForSingleObject()并传递 WaitHandle来将与等待操作相关的工作项排队到线程池中。在这两种情况下,线程池都使用或创建一个后台线程来调用回调方法。
在以下情况,适合于创建并管理自己的线程而不是使用 ThreadPool:
1)如果您需要使一个任务具有特定的优先级。
2)如果您具有可能会长时间运行(并因此阻塞其他任务)的任务。
3)如果您需要将线程放置到单线程单元中(所有 ThreadPool 线程均处于多线程单元中)。
4)如果您需要与线程关联的永久标识。例如,您可能想使用专用线程来中止该线程、将其挂起或按名称发现它。
3. 示例代码
C#
// Copyright (C) Microsoft Corporation. All rights reserved.
// 这个示例是用多线程来计算斐波纳契数列(一种整数数列, 其中每数等于前面两数之和).
using System;
using System.Threading;
// The Fibonacci class provides an interface for using an auxiliary
// thread to perform the lengthy Fibonacci(N) calculation.
// N is provided to the Fibonacci constructor, along with an
// event that the object signals when the operation is complete.
// The result can then be retrieved with the FibOfN property.
public class Fibonacci
... {
public Fibonacci(int n, ManualResetEvent doneEvent)
...{
_n = n;
_doneEvent = doneEvent;
}
// Wrapper method for use with thread pool.
public void ThreadPoolCallback(Object threadContext)
...{
int threadIndex = (int)threadContext;
Console.WriteLine("thread {0} started...", threadIndex);
_fibOfN = Calculate(_n);
Console.WriteLine("thread {0} result calculated...", threadIndex);
_doneEvent.Set();
}
// Recursive method that calculates the Nth Fibonacci number.
public int Calculate(int n)
...{
if (n <= 1)
...{
return n;
}
else
...{
return Calculate(n - 1) + Calculate(n - 2);
}
}
public int N ...{ get ...{ return _n; } }
private int _n;
public int FibOfN ...{ get ...{ return _fibOfN; } }
private int _fibOfN;
ManualResetEvent _doneEvent;
}
public class ThreadPoolExample
... {
static void Main()
...{
const int FibonacciCalculations = 10;
// One event is used for each Fibonacci object
ManualResetEvent[] doneEvents = new ManualResetEvent[FibonacciCalculations];
Fibonacci[] fibArray = new Fibonacci[FibonacciCalculations];
Random r = new Random();
// Configure and launch threads using ThreadPool: 按次序把10个线程放入线程池
// QueueUserWorkItem方法有两个版本,详情请查MSDN:
//ThreadPool.QueueUserWorkItem (WaitCallback)
//ThreadPool.QueueUserWorkItem (WaitCallback, Object)
//i是给回调方法用的带数据对象(就是参数)即i作为参数传给了ThreadPoolCallback()函数
Console.WriteLine("launching {0} tasks...", FibonacciCalculations);
for (int i = 0; i < FibonacciCalculations; i++)
...{
doneEvents[i] = new ManualResetEvent(false);
Fibonacci f = new Fibonacci(r.Next(20,40), doneEvents[i]);
fibArray[i] = f;
ThreadPool.QueueUserWorkItem(f.ThreadPoolCallback, i);
}
// Wait for all threads in pool to calculation...
WaitHandle.WaitAll(doneEvents);
Console.WriteLine("Calculations complete.");
// Display the results...
for (int i= 0; i<FibonacciCalculations; i++)
...{
Fibonacci f = fibArray[i];
Console.WriteLine("Fibonacci({0}) = {1}", f.N, f.FibOfN);
}
}
}