多執行緒能提升回應性、發揮多核效能、隔離阻塞操作。但共享資料存取帶來同步挑戰。本文說明 Windows 執行緒模型、C++Builder TThread 架構、同步物件、經典生產者-消費者模式實作。
| 場景 | 單執行緒痛點 | 多執行緒效益 |
|---|---|---|
| MDI 應用 | 單一視窗阻塞影響全程式 | 每視窗獨立執行緒,互不干擾 |
| 多核 CPU | 僅用單核 | Windows 排程分派至多核並行 |
| 耗時運算/IO | UI 凍結、無回應 | 背景執行緒處理,UI 保持流暢 |
| 網路伺服器 | 序列處理請求,延遲高 | 每連線/請求獨立執行緒/執行緒池 |
Execute()FreeOnTerminate = true 自動釋放物件Synchronize() 或 Queue()TCriticalSection/TMutex/TSemaphore/TEvent 保護| 物件 | 適用場景 | 關鍵方法 |
|---|---|---|
TCriticalSection | 進程內短暫臨界區 | Enter()/Leave(), Acquire()/Release() |
TMutex | 跨進程同步、命名互斥 | WaitFor()/ReleaseMutex() |
TSemaphore | 資源計數控制 (連線池、緩衝區) | WaitFor()/Release() |
TEvent | 執行緒間通知/等待條件 | SetEvent()/ResetEvent()/WaitFor() |
TInterlocked | 原子整數操作 (計數器、旗標) | Increment/Decrement/Exchange/CompareExchange |
場景:緩衝區大小 N。生產者產生資料放入,滿則等待;消費者取出處理,空則等待。
class BoundedBuffer {
std::vector buffer;
size_t capacity;
size_t head = 0, tail = 0, count = 0;
TCriticalSection cs; // 保護緩衝區結構
TEvent notFull; // 生產者等待:緩衝區非滿
TEvent notEmpty; // 消費者等待:緩衝區非空
// 手動重置事件,避免喚醒單一執行緒不足
public:
BoundedBuffer(size_t cap) : capacity(cap), buffer(cap),
notFull(true, false), notEmpty(true, false) {}
void Produce(int value) {
cs.Enter();
try {
while (count == capacity) {
cs.Leave();
notFull.WaitFor(INFINITE); // 等待非滿
cs.Enter();
}
buffer[tail] = value;
tail = (tail + 1) % capacity;
++count;
notEmpty.SetEvent(); // 通知消費者有資料
}
__finally { cs.Leave(); }
}
int Consume() {
int value;
cs.Enter();
try {
while (count == 0) {
cs.Leave();
notEmpty.WaitFor(INFINITE);
cs.Enter();
}
value = buffer[head];
head = (head + 1) % capacity;
--count;
notFull.SetEvent(); // 通知生產者有空位
return value;
}
__finally { cs.Leave(); }
}
};
class ProducerThread : public TThread {
BoundedBuffer& buffer;
int id;
protected:
void __fastcall Execute() {
for (int i = 0; !Terminated && i < 100; ++i) {
int data = id * 1000 + i;
buffer.Produce(data);
Synchronize([=] { Form1->Log("Producer " + IntToStr(id) + " produced " + data); });
Sleep(Random(100));
}
}
public:
__fastcall ProducerThread(BoundedBuffer& buf, int id_, bool suspended)
: TThread(suspended), buffer(buf), id(id_) {}
};
class ConsumerThread : public TThread {
BoundedBuffer& buffer;
int id;
protected:
void __fastcall Execute() {
while (!Terminated) {
int data = buffer.Consume();
Synchronize([=] { Form1->Log("Consumer " + IntToStr(id) + " consumed " + data); });
Sleep(Random(150));
}
}
public:
__fastcall ConsumerThread(BoundedBuffer& buf, int id_, bool suspended)
: TThread(suspended), buffer(buf), id(id_) {}
};
BoundedBuffer buffer(10);
ProducerThread* p1 = new ProducerThread(buffer, 1, false);
ProducerThread* p2 = new ProducerThread(buffer, 2, false);
ConsumerThread* c1 = new ConsumerThread(buffer, 1, false);
ConsumerThread* c2 = new ConsumerThread(buffer, 2, false);
// 結束時 Terminate + WaitFor
#include <mutex>
#include <condition_variable>
#include <queue>
class ModernBuffer {
std::queue q;
size_t capacity;
std::mutex mtx;
std::condition_variable notFull, notEmpty;
public:
ModernBuffer(size_t cap) : capacity(cap) {}
void Produce(int v) {
std::unique_lock lk(mtx);
notFull.wait(lk, [&]{ return q.size() < capacity; });
q.push(v);
notEmpty.notify_one();
}
int Consume() {
std::unique_lock lk(mtx);
notEmpty.wait(lk, [&]{ return !q.empty(); });
int v = q.front(); q.pop();
notFull.notify_one();
return v;
}
};
std::mutex + std::condition_variable 為標準、可攜、型別安全std::unique_lock 配合 wait(predicate) 自動處理虛假喚醒SetThreadName(-1, "Producer-1"); (需自定義函數)TMonitor / std::mutex 無內建,需記錄鎖順序、超時機制ThreadSanitizer (Clang/GCC) 或 Concurrency Visualizer (VS)GetCurrentThreadId()多執行緒威力巨大,同步正確性是生命線。掌握 TCriticalSection/TEvent 等 VCL 同步物件、經典模式 (生產者-消費者、讀寫鎖、未來/承諾)、現代 C++ 標準庫替代方案,並養成「鎖最小化、避免巢狀鎖、RAII 管理鎖」習慣,才能駕馭並行複雜度。