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);
}
}
}