TKeed threadpool_worker函數淺析

該函數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;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章