生產者消費者編程實現,採用了線程池以及訊號量技術。
線程的概念就不多說,首先說一下多線程的好處:多線程技術主要解決處理器單元內多個線程執行的問題,它可以顯著減少處理器單元的閑置時間,增加處理器單元的吞吐能力。
那麼為什麼又需要線程池呢?
我們知道應用程式建立一個對象,然後銷毀對象是很耗費資源的。建立線程,銷毀線程,也是如此。因此,我們就預先產生一些線程,等到我們使用的時候在進行調度,於是,一些"池化資源"技術就這樣的產生了。
一般一個簡單線程池至少包含下列組成部分。
1) 線程池管理器(ThreadPoolManager):用於建立並管理線程池
2) 背景工作執行緒(WorkThread): 線程池中線程
3) 任務介面(Task):每個任務必須實現的介面,以供背景工作執行緒調度任務的執行。
4) 任務隊列:用於存放沒有處理的任務。提供一種緩衝機制。
圖示:
圖1 線程池圖解
生產者消費者模型C語言代碼實現:
thread_pool_pv.h:
//線程池編程實現#ifndef THREAD_POOL_H#define THREAD_POOL_H#include <stdio.h>#include <stdlib.h>#include <semaphore.h>//訊號量sem_t#include <pthread.h>//任務介面,線程調用的函數typedef void* (*FUNC)(void *arg);//任務資料結構typedef struct thread_pool_job_s{ FUNC function;//線程調用的函數 void *arg;//函數參數 struct thread_pool_job_s *pre;//指向上一個節點 struct thread_pool_job_s *next;//指向下一個節點}thread_pool_job;//工作隊列typedef struct thread_pool_job_queue_s{ thread_pool_job *head;//隊列頭指標 thread_pool_job *tail;//隊列尾指標 int num;//任務數目 sem_t *quene_sem;//訊號量}thread_pool_job_queue;//線程池(存放消費者進程)typedef struct thread_pool_s{ pthread_t *threads;//線程 int threads_num;//線程數目 thread_pool_job_queue *job_queue;//指向工作隊列的指標}thread_pool;//typedef struct thread_data_s{// pthread_mutex_t *mutex_t;//互斥量// thread_pool *tp_p;//指向線程池的指標//}thread_data;//初始化線程池thread_pool* tp_init(int thread_num);//初始化工作隊列int tp_job_quene_init(thread_pool *tp);//向工作隊列中添加一個元素void tp_job_quene_add(thread_pool *tp,thread_pool_job *new_job);//向線程池中添加一個工作項目int tp_add_work(thread_pool *tp,void *(*func_p)(void *),void *arg);//取得工作隊列的最後個節點thread_pool_job* tp_get_lastjob(thread_pool *tp);//刪除工作隊列的最後個節點int tp_delete__lastjob(thread_pool *tp);//銷毀線程池void tp_destroy(thread_pool *tp);//消費者線程函數void* tp_thread_func(thread_pool *tp);//生產者線程執行函數void* thread_func_producer(thread_pool *tp);#endif
thread_pool_pv.c:
//線程池編程實現#include "thread_pool.h"//互斥量,用於對工作隊列的訪問pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//標記線程池是否處於可用狀態static int tp_alive = 1;//初始化線程池thread_pool* tp_init(int thread_num){ thread_pool *tp; int i; if(thread_num < 1) thread_num = 1; tp = (thread_pool *)malloc(sizeof(thread_pool)); //判斷記憶體配置是否成功 if(NULL == tp){ printf("ERROR:allocate memory for thread_pool failed\n"); return NULL; } tp->threads_num = thread_num; //分配線程所佔記憶體空間 tp->threads = (pthread_t*)malloc(thread_num * sizeof(pthread_t)); //判斷記憶體配置是否成功 if(NULL == tp->threads){ printf("ERROR:allocate memory for threads in thread pool failed\n"); return NULL; } if(tp_job_quene_init(tp)) return NULL; tp->job_queue->quene_sem = (sem_t *)malloc(sizeof(sem_t)); sem_init(tp->job_queue->quene_sem,0,0);//訊號量初始化 //初始化線程 for(i = 0;i < thread_num;++i){ pthread_create(&(tp->threads[i]),NULL,(void *)tp_thread_func,(void *)tp); } return tp;}//初始化工作隊列int tp_job_quene_init(thread_pool *tp){ tp->job_queue = (thread_pool_job_queue *)malloc(sizeof(thread_pool_job_queue)); if(NULL == tp->job_queue){ return -1; } tp->job_queue->head = NULL; tp->job_queue->tail = NULL; tp->job_queue->num = 0; return 0;}//線程函數void* tp_thread_func(thread_pool *tp){ FUNC function; void *arg_buf; thread_pool_job *job_p; while(tp_alive){ //線程阻塞,等待訊號量 if(sem_wait(tp->job_queue->quene_sem)){ printf("thread waiting for semaphore....\n"); exit(1); } if(tp_alive){ pthread_mutex_lock(&mutex); job_p = tp_get_lastjob(tp); if(NULL == job_p){ pthread_mutex_unlock(&mutex); continue; } function = job_p->function; arg_buf = job_p->arg; if(tp_delete__lastjob(tp)) return; pthread_mutex_unlock(&mutex); //運行指定的線程函數 printf("consumer...get a job from job quene and run it!\n"); function(arg_buf); free(job_p); } else return; } return;}//向工作隊列中添加一個元素void tp_job_quene_add(thread_pool *tp,thread_pool_job *new_job){ new_job->pre = NULL; new_job->next = NULL; thread_pool_job *old_head_job = tp->job_queue->head; if(NULL == old_head_job){ tp->job_queue->head = new_job; tp->job_queue->tail = new_job; } else{ old_head_job->pre = new_job; new_job->next = old_head_job; tp->job_queue->head = new_job; } ++(tp->job_queue->num); sem_post(tp->job_queue->quene_sem);}//取得工作隊列的最後一個節點thread_pool_job* tp_get_lastjob(thread_pool *tp){ return tp->job_queue->tail;}//刪除工作隊列的最後個節點int tp_delete__lastjob(thread_pool *tp){ if(NULL == tp) return -1; thread_pool_job *last_job = tp->job_queue->tail; if(0 == tp->job_queue->num){ return -1; } else if(1 == tp->job_queue->num){ tp->job_queue->head = NULL; tp->job_queue->tail = NULL; } else{ last_job->pre->next = NULL; tp->job_queue->tail = last_job->pre; } //修改相關變數 --(tp->job_queue->num); return 0;}//向線程池中添加一個工作項目int tp_add_work(thread_pool *tp,void *(*func_p)(void *),void *arg){ thread_pool_job *new_job = (thread_pool_job *)malloc(sizeof(thread_pool_job)); if(NULL == new_job){ printf("ERROR:allocate memory for new job failed!\n"); exit(1); } new_job->function = func_p; new_job->arg = arg; pthread_mutex_lock(&mutex); tp_job_quene_add(tp,new_job); pthread_mutex_unlock(&mutex);}//銷毀線程池void tp_destroy(thread_pool *tp){ int i; tp_alive = 0; //等待線程運行結束 //sleep(10); for(i = 0;i < tp->threads_num;++i){ pthread_join(tp->threads[i],NULL); } free(tp->threads); if(sem_destroy(tp->job_queue->quene_sem)){ printf("ERROR:destroy semaphore failed!\n"); } free(tp->job_queue->quene_sem); //刪除job隊列 thread_pool_job *current_job = tp->job_queue->tail; while(tp->job_queue->num){ tp->job_queue->tail = current_job->pre; free(current_job); current_job = tp->job_queue->tail; --(tp->job_queue->num); } tp->job_queue->head = NULL; tp->job_queue->tail = NULL;}//自訂線程執行函數void* thread_func1(){ printf("Task1 running...by Thread :%u\n",(unsigned int)pthread_self());}//自訂線程執行函數void* thread_func2(){ printf("Task2 running...by Thread :%u\n",(unsigned int)pthread_self());}//生產者線程執行函數void* thread_func_producer(thread_pool *tp){ while(1){ printf("producer...add a job(job1) to job quene!\n"); tp_add_work(tp,(void*)thread_func1,NULL); sleep(1); printf("producer...add a job(job2) to job quene!\n"); tp_add_work(tp,(void*)thread_func2,NULL); }}int main(){ thread_pool *tp = tp_init(5); int i; int arg = 7; pthread_t producer_thread_id;//生產者線程ID pthread_create(&producer_thread_id,NULL,(void *)thread_func_producer,(void *)tp); pthread_join(producer_thread_id,NULL); tp_destroy(tp); return 0;}
運行結果: