C#多線程之線程池ThreadPool詳解
一、ThreadPool概述
提供一個(gè)線程池,該線程池可用于執(zhí)行任務(wù)、發(fā)送工作項(xiàng)、處理異步 I/O、代表其他線程等待以及處理計(jì)時(shí)器。
創(chuàng)建線程需要時(shí)間。如果有不同的小任務(wù)要完成,就可以事先創(chuàng)建許多線程/在應(yīng)完成這些任務(wù)時(shí)發(fā)出請(qǐng)求。不需要自己創(chuàng)建這樣一個(gè)列表。該列表由ThreadPool類(lèi)托管。
這個(gè)類(lèi)會(huì)在需要時(shí)增減池中線程的線程數(shù),直到最大的線程數(shù)。池中的最大線程數(shù)是可配置的。在雙核CPU中,默認(rèn)設(shè)置為1023 個(gè)工作線程和1000個(gè)I/O線程。也可以指定在創(chuàng)建線程池時(shí)應(yīng)立即啟動(dòng)的最小線程數(shù),以及線程池 中可用的最大線程數(shù)。
如果有更多的作業(yè)要處理,線程池中線程的個(gè)數(shù)也達(dá)到了極限,最新的作業(yè)就要排隊(duì),且必須等待線程完成其任務(wù)。
線程池使用起來(lái)很簡(jiǎn)單,但它有一些限制:
- 線程池中的所有線程都是后臺(tái)線程。如果進(jìn)程的所有前臺(tái)線程都結(jié)束了,所有的后臺(tái)線程 就會(huì)停止。不能把入池的線程改為前臺(tái)線程。
- 不能給入池的線程設(shè)置優(yōu)先級(jí)或名稱(chēng)。
- 對(duì)于COM對(duì)象,入池的所有線程都是多線程單元(multithreaded apartment, MTA)線程。許 多COM對(duì)象都需要單線程單元(single-threaded apartment, MTA)線程。
- 入池的線程只能用于時(shí)間較短的任務(wù)。如果線程要一直運(yùn)行(如Word的拼寫(xiě)檢杳器線程), 就應(yīng)使用Thread類(lèi)創(chuàng)建一個(gè)線程.
使用線程池線程的操作的情況包括:
- 當(dāng)您創(chuàng)建Task或Task<TResult>對(duì)象以異步方式執(zhí)行某項(xiàng)任務(wù),默認(rèn)情況下任務(wù)調(diào)度在線程池線程上運(yùn)行的。
- 異步計(jì)時(shí)器使用線程池。 線程池線程從System.Threading.Timer類(lèi)執(zhí)行回調(diào),和從System.Timers.Timer類(lèi)引發(fā)事件。
- 當(dāng)使用已注冊(cè)的等待句柄時(shí),系統(tǒng)線程監(jiān)視等待句柄的狀態(tài)。 等待操作完成后,從線程池的工作線程將執(zhí)行相應(yīng)的回調(diào)函數(shù)。
- 當(dāng)您調(diào)用QueueUserWorkItem方法進(jìn)行排隊(duì),以在線程池線程上執(zhí)行的方法。 為此,可將該方法傳遞WaitCallback委托。
二、方法
GetAvailableThreads(Int32, Int32)
檢索由 GetMaxThreads(Int32, Int32) 方法返回的最大線程池線程數(shù)和當(dāng)前活動(dòng)線程數(shù)之間的差值。GetMaxThreads(Int32, Int32)
檢索可以同時(shí)處于活動(dòng)狀態(tài)的線程池請(qǐng)求的數(shù)目。 所有大于此數(shù)目的請(qǐng)求將保持排隊(duì)狀態(tài),直到線程池線程變?yōu)榭捎谩?/li>SetMaxThreads(Int32, Int32)
設(shè)置可以同時(shí)處于活動(dòng)狀態(tài)的線程池的請(qǐng)求數(shù)目。 所有大于此數(shù)目的請(qǐng)求將保持排隊(duì)狀態(tài),直到線程池線程變?yōu)榭捎谩?/li>GetMinThreads(Int32, Int32)
發(fā)出新的請(qǐng)求時(shí),在切換到管理線程創(chuàng)建和銷(xiāo)毀的算法之前檢索線程池按需創(chuàng)建的線程的最小數(shù)量。SetMinThreads(Int32, Int32)
發(fā)出新的請(qǐng)求時(shí),在切換到管理線程創(chuàng)建和銷(xiāo)毀的算法之前設(shè)置線程池按需創(chuàng)建的線程的最小數(shù)量。QueueUserWorkItem(WaitCallback, Object)
將方法排入隊(duì)列以便執(zhí)行,并指定包含該方法所用數(shù)據(jù)的對(duì)象。 此方法在有線程池線程變得可用時(shí)執(zhí)行。RegisterWaitForSingleObject(WaitHandle, WaitOrTimerCallback, Object, Int32, Boolean)
注冊(cè)一個(gè)等待 WaitHandle 的委托,并指定一個(gè) 32 位有符號(hào)整數(shù)來(lái)表示超時(shí)值(以毫秒為單位)。
三、獲取線程數(shù)方法
int i = 0; int j = 0; //前面是輔助(也就是所謂的工作者)線程,后面是I/O線程 ThreadPool.GetMaxThreads(out i, out j); Console.WriteLine(i.ToString() + " " + j.ToString()); //默認(rèn)都是1000 //獲取空閑線程,由于現(xiàn)在沒(méi)有使用異步線程,所以為空 ThreadPool.GetAvailableThreads(out i, out j); Console.WriteLine(i.ToString() + " " + j.ToString()); //默認(rèn)都是1000
四、QueueUserWorkItem(WaitCallback, Object)
將方法排入隊(duì)列以便執(zhí)行,并指定包含該方法所用數(shù)據(jù)的對(duì)象。 此方法在有線程池線程變得可用時(shí)執(zhí)行。
public static bool QueueUserWorkItem (System.Threading.WaitCallback callBack, object state);
實(shí)例:
static void Main(string[] args)
{
Person p = new Person(1, "劉備");
//啟動(dòng)工作者線程
ThreadPool.QueueUserWorkItem(new WaitCallback(RunWorkerThread), p);
}
static void RunWorkerThread(object obj)
{
Thread.Sleep(200);
Console.WriteLine("線程池線程開(kāi)始!");
Person p = obj as Person;
Console.WriteLine(p.Name);
}
public class Person
{
public Person(int id, string name) { Id = id; Name = name; }
public int Id { get; set; }
public string Name { get; set; }
}五、RegisterWaitForSingleObject 注冊(cè)等待句柄
注冊(cè)一個(gè)等待 WaitHandle 的委托,并指定一個(gè)數(shù)來(lái)表示超時(shí)值(以毫秒為單位)。
將指定的方法排隊(duì)到線程池,當(dāng)超時(shí)或者等待委托接收到信號(hào)時(shí),輔助線程將執(zhí)行此方法,即主線程控制輔助線程什么時(shí)候開(kāi)始執(zhí)行。
public static System.Threading.RegisteredWaitHandle RegisterWaitForSingleObject (System.Threading.WaitHandle waitObject, System.Threading.WaitOrTimerCallback callBack, object state, int millisecondsTimeOutInterval, bool executeOnlyOnce);
參數(shù)
waitObject
要注冊(cè)的 WaitHandle。 使用 WaitHandle 而非 Mutex。callBack
向 waitObject 參數(shù)發(fā)出信號(hào)時(shí)調(diào)用的 WaitOrTimerCallback 委托。state
傳遞給委托的對(duì)象。millisecondsTimeOutInterval
以毫秒為單位的超時(shí)。 如果 millisecondsTimeOutInterval 參數(shù)為 0(零),函數(shù)將測(cè)試對(duì)象的狀態(tài)并立即返回。 如果 millisecondsTimeOutInterval 為 -1,則函數(shù)的超時(shí)間隔永遠(yuǎn)不過(guò)期。
表示間隔幾秒執(zhí)行回調(diào)方法,指當(dāng)剛加入線程后,它是需要過(guò)了幾秒后才會(huì)第一次執(zhí)行回調(diào)方法。如果使用了wait.Set()方法使用立即執(zhí)行回調(diào)函數(shù)而不需要等待。executeOnlyOnce
如果為 true,表示在調(diào)用了委托后,線程將不再在 waitObject 參數(shù)上等待;如果為 false,表示每次完成等待操作后都重置計(jì)時(shí)器,直到注銷(xiāo)等待。
返回
RegisteredWaitHandle
封裝本機(jī)句柄的 RegisteredWaitHandle。
// TaskInfo contains data that will be passed to the callback method.
public class TaskInfo
{
public RegisteredWaitHandle Handle = null;
public string OtherInfo = "default";
}
public static void Main(string[] args)
{
// 主線程使用AutoResetEvent來(lái)給已注冊(cè)的等待句柄發(fā)信號(hào), 此等待句柄執(zhí)行回調(diào)方法
AutoResetEvent ev = new AutoResetEvent(false);
TaskInfo ti = new TaskInfo();
ti.OtherInfo = "First task";
// The TaskInfo for the task includes the registered wait handle returned by RegisterWaitForSingleObject. This
// allows the wait to be terminated when the object has been signaled once (see WaitProc).
ti.Handle = ThreadPool.RegisterWaitForSingleObject(
ev,
new WaitOrTimerCallback(WaitProc),
ti,
1000,
false
);
// 主線程等待三秒,為了演示隊(duì)列中的線程超時(shí),然后發(fā)信號(hào).
Thread.Sleep(3100);
Console.WriteLine("Main thread signals.");
ev.Set();//發(fā)信號(hào)
// The main thread sleeps, which should give the callback method time to execute. If you comment out this line, the program usually ends before the ThreadPool thread can execute.
Thread.Sleep(1000);
// If you start a thread yourself, you can wait for it to end by calling Thread.Join. This option is not available with thread pool threads.
}
//The callback method executes when the registered wait times out,
//or when the WaitHandle (in this case AutoResetEvent) is signaled.
//WaitProc unregisters the WaitHandle the first time the event is signaled.
public static void WaitProc(object state, bool timedOut)
{
TaskInfo ti = (TaskInfo)state;
string cause = "TIMED OUT";
if (!timedOut) //如果Timeout為false,表示接收到的信號(hào)后執(zhí)行的
{
cause = "SIGNALED";
//如果回調(diào)方法執(zhí)行的話(huà)是因?yàn)閃aitHandle觸發(fā)信號(hào)的話(huà),則用反注冊(cè)等待句柄來(lái)取消回調(diào)方法將來(lái)的執(zhí)行。
if (ti.Handle != null)
ti.Handle.Unregister(null);//
}
Console.WriteLine("WaitProc( {0} ) executes on thread {1}; cause = {2}.",
ti.OtherInfo, Thread.CurrentThread.GetHashCode().ToString(), cause);//超時(shí)后執(zhí)行的
}結(jié)果如下:
WaitProc( First task ) executes on thread 7; cause = TIMED OUT.
WaitProc( First task ) executes on thread 7; cause = TIMED OUT.
WaitProc( First task ) executes on thread 7; cause = TIMED OUT.
Main thread signals.
WaitProc( First task ) executes on thread 7; cause = SIGNALED.
到此這篇關(guān)于C#多線程之線程池ThreadPool的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
用C#做網(wǎng)絡(luò)爬蟲(chóng)的步驟教學(xué)
在本篇內(nèi)容里小編給大家分享的是關(guān)于用C#做網(wǎng)絡(luò)爬蟲(chóng)的步驟和方法,需要的朋友們可以參考下。2018-12-12
基于C#解決庫(kù)存扣減及訂單創(chuàng)建時(shí)防止并發(fā)死鎖的問(wèn)題
這篇文章主要介紹了基于C#解決庫(kù)存扣減及訂單創(chuàng)建時(shí)防止并發(fā)死鎖的問(wèn)題,很多開(kāi)發(fā)人員對(duì)于這個(gè)問(wèn)題的排查起來(lái)是比較困難的,而生產(chǎn)生的原因多種多樣,很多人認(rèn)是因?yàn)楸碇械臄?shù)據(jù)太多了同時(shí)操作的人多人才會(huì)產(chǎn)生這種錯(cuò)誤,下面我們來(lái)還原一下死鎖的過(guò)程2022-05-05
c#中Invoke與BeginInvoke的用法及說(shuō)明
這篇文章主要介紹了c#中Invoke與BeginInvoke的用法及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01

