該函數API:
void *threadpool_worker(void *arg)
arg存的是pthread_create傳給threadpool_worker函數的線程池指針。
該函數幹什麼?
僞代碼簡單的說明一下:
while(1){
鎖
取任務
更新池變量
開鎖
設置task參數
}
更新池變量
開鎖
退出線程
返回
逐一分析:
1、鎖。使用線程池裏的公用鎖
2、取任務。等等…有任務嗎?
線程如何知道是否有任務?
pool->queue_size == 0表示無任務,否則表示有任務,queue就是任務鏈表(或者說隊列),queue_size是由線程池單獨維護的一個變量,用於記錄尚未被工作線程接手的任務數
有任務,就可以執行了嗎?如果線程池現在是關機狀態呢?請問現在開機了嗎?
pool->shutdown == 1表示線程池此時是關機狀態,否則是開機狀態
while(開機&&無任務)
等待條件變量//pthread_cond_wait(&(pool->cond), &(pool->lock));
跳出上述while循環,也許是因爲來任務了,也許是因爲關機了
那麼,是下面這樣嗎?
if(關機)
break
else
執行任務
等一下!有很重要的任務沒完成!關機之前必須做完!
如果有些任務必須在關機前完成,或者關機並不急切 ,上述的關機模式似乎太過武斷。
因此引入了優雅關機和立即關機。
// 立即停機模式、平滑停機且沒有未完成任務則退出
if (pool->shutdown == immediate_shutdown)
break;
else if ((pool->shutdown == graceful_shutdown) && (pool->queue_size == 0))
break;
區別在於,優雅關機會等待任務鏈表清空,即工作全部被接手(或者已完成)。
至此,已知開機(或者優雅關機)且有任務,剩下的就是如何從線程池的任務鏈表裏取走任務了
// 得到第一個task
task = pool->head->next;
// 沒有task則開鎖並進行下一次循環
if (task == NULL) {
pthread_mutex_unlock(&(pool->lock));
continue;
}
// 存在task則取走並開鎖
pool->head->next = task->next;
pool->queue_size--;
需要注意:
pool->head並不指向任何任務,pool->head->next指向第一個待接手任務,取走任務實際上就是,將任務鏈表裏的待接手任務賦值給線程自身的task指針
3、更新池變量。取走任務後,需要更新pool->head->next,使得它指向下個任務(也許不存在),更新任務鏈表長度(pool->queue_size自減)
4、開鎖。
pthread_mutex_unlock(&(pool->lock));
5、設置task參數。(由於是本地的task,不在臨界區內,因此可以無風險的在開鎖後設置task參數)
(*(task->func))(task->arg);
free(task);
6、更新池變量。此時已經出循環了,無論線程是否取到了任務,都需要自減pool->started變量,表示工作線程減一
7、開鎖
8、退出線程
//7.8.兩步
pthread_mutex_unlock(&(pool->lock));
pthread_exit(NULL);
return NULL;