本文展示一個基於 POSIX 線程(pthread)的線程池範例:多個計算線程 產生數列項(1/i),兩個消費者線程 分別執行「累加」與「交替加減」聚合,透過條件變量 + 互斥鎖同步,其中一個消費者採用超時等待機制。程式可直接編譯執行,輸出完整計算過程。
#define MAXS 1000
#define MAXTDS 5 // 線程池大小
double myjg[MAXS + 1]; // myjg[0] 存當前已計算索引 i,myjg[1..i] 存 1/i
int max; // 用戶輸入 N
pthread_mutex_t eventlock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t myevent = PTHREAD_COND_INITIALIZER;
pthread_t threads[MAXTDS + 2]; // 5 計算 + 2 消費者
int isend = 0; // 計算結束旗標
mycomp(5 個)i。1.0 / i 存入 myjg[i],更新 myjg[0]。MAXTDS 次或最後一項時,pthread_cond_broadcast 喚醒消費者。isend=1 並 signal 結束。myprint1(超時等待)void *myprint1(void *arg) {
int cur = 1;
double sum = 0;
struct timeval now;
struct timespec timeout;
while (cur <= max) {
gettimeofday(&now);
timeout.tv_sec = now.tv_sec + 1; // 1 秒超時
timeout.tv_nsec = now.tv_usec * 1000;
pthread_mutex_lock(&eventlock);
int rc = pthread_cond_timedwait(&myevent, &eventlock, &timeout);
if (rc == 0) {
int ready = (int)myjg[0];
pthread_mutex_unlock(&eventlock);
for (; cur <= ready; cur++) {
sum += myjg[cur];
printf("1/%d: %.10f added result %.10f\n", cur, myjg[cur], sum);
}
} else if (rc == ETIMEDOUT) {
printf("time out\n");
pthread_mutex_unlock(&eventlock);
} else {
pthread_mutex_unlock(&eventlock);
}
}
printf("================add finish!============ result: %.10f\n", sum);
return NULL;
}
超時機制意義:避免永久阻塞,定期輪詢可實現心跳、進度顯示、優雅取消。
myprint2(無限等待)void *myprint2(void *arg) {
int cur = 1;
double sum = 0;
int sign = 1;
while (cur <= max) {
sleep(2); // 模擬較慢處理
pthread_mutex_lock(&eventlock);
int rc = pthread_cond_wait(&myevent, &eventlock); // 永久等待
if (rc == 0) {
int ready = (int)myjg[0];
pthread_mutex_unlock(&eventlock);
for (; cur <= ready; cur++) {
sum += sign * myjg[cur];
printf("*******1/%d: %.10f computed result %.10f\n", cur, myjg[cur], sum);
sign = -sign;
}
printf("===============compute finish!=========== result: %.10f\n", sum);
} else {
pthread_mutex_unlock(&eventlock);
}
}
return NULL;
}
int main() {
pthread_mutex_init(&eventlock, NULL);
pthread_cond_init(&myevent, NULL);
printf("please input an integer:(<=%d) ", MAXS);
while (scanf("%d", &max), max > MAXS) {
printf("please input an integer:(<=%d) ", MAXS);
}
myjg[0] = 0;
int i = 0;
pthread_create(&threads[i++], NULL, myprint1, NULL); sleep(1);
pthread_create(&threads[i++], NULL, myprint2, NULL); sleep(1);
for (; i <= MAXTDS; i++) {
pthread_create(&threads[i], NULL, mycomp, NULL);
sleep(1);
}
sleep(MAXTDS * 2 * (i/10 + 1)); // 等待完成
pthread_mutex_destroy(&eventlock);
pthread_cond_destroy(&myevent);
return 0;
}
please input an integer:(<=1000)26
time out
time out
1/1 finished,push 1.0000000000
1/2 finished,push 0.5000000000
...
1/1:1.0000000000 added result 1.0000000000
1/2:0.5000000000 added result 1.5000000000
...
*******1/1:1.0000000000 computed result 1.0000000000
*******1/2:0.5000000000 computed result 0.5000000000
...
===============compute finish!=========== result:0.7253718504
| 機制 | 用途 | 關鍵點 |
|---|---|---|
互斥鎖 eventlock | 保護共享陣列 myjg 與旗標 isend | cond_wait 內部自動解鎖/重鎖 |
條件變量 myevent | 生產者通知消費者「有新資料」 | broadcast 喚醒所有等待者;signal 喚醒一個 |
timedwait | 消費者 1 超時輪詢 | 需轉換 timeval→timespec(納秒) |
wait | 消費者 2 永久阻塞 | 較簡單,但無法響應外部取消 |
pthread_cond_wait/timedwait 入參鎖需已鎖定,函式內部原子性解鎖並休眠,被喚醒後重新加鎖返回。ready 索引檢查)。broadcast;僅需一個處理用 signal,避免驚群效應。destroy 鎖與條件變量,避免洩漏。gcc -D_REENTRANT -lpthread -o threadpool threadpool.c
./threadpool
ThreadPool::submit(task) 介面。pthread_condattr_setclock 指定單調時鐘,避免系統時間調整影響超時。epoll + 線程池(Reactor 模式)在高併發網路服務中的表現。