多執行緒是建構大型系統時必須重點關注的關鍵技術,尤其在效率(系統跑多快?)與效能(系統運作是否正常?)之間取得平衡時。恰當運用多執行緒能大幅提升系統效能。
系統上每個正在執行的程式都是一個行程。每個行程包含一到多個執行緒。行程也可以是整個程式或部分程式的動態執行。執行緒是一組指令的集合,或程式的特定區段,能在程式內獨立執行,也可視為程式碼執行的上下文。因此執行緒本質上是輕量級行程,負責在單一程式內實現多工。通常由作業系統負責多執行緒的排程與執行。
多執行緒旨在讓多個執行緒並行工作以完成多項任務,提升系統效率。當同一時間需要完成多項任務時,便會實現多執行緒。
一個行程僅能有一個執行緒,其餘行程必須等待當前執行緒結束。缺點:完成微小任務也需佔用極長時間。
一個程式可包含多個執行緒,每個執行緒被劃分為行程內的一個單元。行程可包含多個單元,可共享單元間資料。所有請求透過 Windows 訊息佇列序列化,確保同一時間僅存取一個單元,故同一時間僅有一個執行緒執行。優於單執行緒模型可同時響應多用戶請求,但因序列化導致效能仍非最佳。
每個行程只有一個單元,但該單元控制多個執行緒。無需訊息佇列,所有執行緒屬於同一單元可直接共享資料。執行速度優於 STA,降低系統負載、減少閒置時間。但程式複雜度較高,開發者需自行提供執行緒同步機制(如鎖)避免競爭條件,且可能導致死結。
.NET 本質上是多執行緒環境,提倡兩種主要方式:
ThreadStart 建立自有執行緒(手動管理)。ThreadPool.QueueUserWorkItem)或間接(如 Stream.BeginRead、BeginInvoke)使用執行緒集區(ThreadPool)。一般建議:長時間執行的任務手動建立新執行緒;短時間、頻繁啟動的任務優先使用執行緒集區。集區可同時執行多項任務、善用框架類別,並在資源稀缺需同步時限制同一時間僅允許單一執行緒存取資源(實現鎖機制)。執行緒基底類別為 System.Threading,所有執行緒透過 CLI 管理。
Thread dummyThread = new Thread(new ThreadStart(DummyFunction));
dummyThread.Start();
dummyPriorityThread.Join();
dummyPriorityThread.Sleep(<毫秒數>);
dummyPriorityThread.Abort();
常見同步方式包括:
Interlocked 類別:提供原子操作實現鎖機制,如 Interlocked.Increment(ref counter)。lock 關鍵字:鎖定關鍵程式碼區塊,lock(this) { ... }。Monitor 類別:Monitor.Enter(this) 等進階控制。以下範例展示基本同步情境:
using System;
using System.Threading;
namespace SynchronizationThreadsExample
{
class SynchronizationThreadsExample
{
private int counter = 0;
static void Main()
{
var STE = new SynchronizationThreadsExample();
STE.ThreadFunction();
}
public void ThreadFunction()
{
Thread dummyThread = new Thread(new ThreadStart(SomeFunction));
dummyThread.IsBackground = true;
dummyThread.Name = "First Thread";
dummyThread.Start();
Console.WriteLine("Started thread {0}", dummyThread.Name);
Thread dummyPriorityThread = new Thread(new ThreadStart(SomeFunction));
dummyPriorityThread.IsBackground = true;
dummyPriorityThread.Name = "Second Thread";
dummyPriorityThread.Start();
Console.WriteLine("Started thread {0}", dummyPriorityThread.Name);
dummyThread.Join();
dummyPriorityThread.Join();
}
public void SomeFunction()
{
try
{
while (counter < 10)
{
int tempCounter = counter;
tempCounter++;
Thread.Sleep(1);
counter = tempCounter;
Console.WriteLine("Thread {0}. SomeFunction: {1}", Thread.CurrentThread.Name, counter);
}
}
catch (ThreadInterruptedException ex)
{
Console.WriteLine("Exception in thread {0}", Thread.CurrentThread.Name);
}
finally
{
Console.WriteLine("Thread {0} Exiting.", Thread.CurrentThread.Name);
}
}
}
}