執行緒池是高併發伺服器開發的基礎設施。本文深入探討如何設計一個避免驚群效應、支援跨平台、具備完整建構/銷毀/任務提交介面的 C 執行緒池,參考 POSIX pthread 標準,並提供完整原始碼與測試驗證。
驚群:多個執行緒同時在條件變數上等待,單一事件觸發喚醒所有等待執行緒,導致大量上下文切換與資源爭搶,嚴重降低效能。
傳統 pthread_cond_signal 可能喚醒多個執行緒。本設計為每個工作執行緒分配獨立條件變數,任務派發時精確喚醒單一閒置執行緒,徹底消除驚群。
// 任務節點
struct threadjob {
vdel_f run; // 任務函式
void *arg; // 任務參數
struct threadjob *next; // 下一任務
};
// 工作執行緒節點(含專屬條件變數)
struct thread {
pthread_t tid; // 執行緒 ID
pthread_cond_t cond; // 專屬條件變數
struct thread *next; // 下一執行緒
};
// 執行緒池管理器
struct threadpool {
int size; // 最大執行緒數
int curr; // 目前總執行緒數
int idle; // 目前閒置執行緒數
pthread_mutex_t mutex; // 全域互斥鎖
struct thread *threads; // 執行緒鏈表
struct threadjob *head; // 任務隊列頭
struct threadjob *tail; // 任務隊列尾
};
_thread_addstruct thread,初始化條件變數sp_addidle > 0):
pthread_cond_signal 喚醒第一個執行緒(頭節點)curr < size):
_consumer_consumerstatic void *_consumer(struct threadpool *pool) {
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
pthread_detach(pthread_self());
pthread_cleanup_push((vdel_f)pthread_mutex_unlock, &pool->mutex);
pthread_mutex_lock(&pool->mutex);
pthread_cond_t *cnd = _thread_get(pool, pthread_self());
while (1) {
if (pool->head) {
// 取出任務
struct threadjob *job = pool->head;
pool->head = job->next;
if (pool->tail == job) pool->tail = NULL;
pthread_mutex_unlock(&pool->mutex);
job->run(job->arg); // 執行任務(無鎖)
free(job);
pthread_mutex_lock(&pool->mutex);
continue;
}
// 無任務:進入等待
pool->idle++;
int status = pthread_cond_wait(cnd, &pool->mutex);
pool->idle--;
if (status == 0) continue; // 正常喚醒
// 異常/取消:清理退出
pool->curr--;
_thread_del(pool, cnd);
pthread_mutex_unlock(&pool->mutex);
pthread_cleanup_pop(0);
return NULL;
}
}
sp_delpthread_cancel、銷毀條件變數、釋放節點NULL透過 schead.h 封裝平台差異:
usleep(ms*1000) / Windows Sleep(ms)gettimeofday / Windows 自行實作__sync_* 內建函式 / Windows Interlocked* APIpthread_cleanup_push/pop 兩平台實作不同,統一巨集介面// 建立池(預設 128 執行緒) threadpool_t pool = sp_NEW(); // 巨集簡化 // 提交任務(自動轉型 void*(*)(void*)) sp_ADD(pool, my_task, arg); // 銷毀池 sp_del(&pool);
測試程式提交 10,000 個任務,混合同步/非同步模式,5 秒後銷毀池。Windows/Linux 雙平台編譯通過,輸出顯示任務正確分發執行。
schead.h/c:跨平台基礎設施(原子鎖、時間、錯誤處理、工具巨集)scpthread.h/c:執行緒池核心實作test_scpthread.c:壓力測試Makefile:自動化建構_thread_get 目前 O(N) 鏈表遍歷,可改用陣列或雜湊表 O(1)epoll/IOCP 實現非同步 I/O 執行緒池本實作展示了工業級執行緒池的核心設計思維:精確喚醒避免驚群、RAII 風格資源管理、跨平台抽象層、完整生命週期控制。原始碼可直接整合至專案,或作為進階多執行緒程式設計的教學範本。