// // Created by lgy on 2020-03-16. // #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <pthread.h> #include <string.h> typedef struct { void (*task_cb)(void *arg); void *arg; }st_task; typedef struct { int max_tasks_cnt; int runing_tasks_cnt; st_task *tasks; int taskhead; int tasktail; pthread_t *threads; int threadcnt; int shutdown; pthread_mutex_t threadpool_lock; pthread_cond_t empty_task;//消耗任务条件变量 pthread_cond_t set_task; //加任务条件变量 }st_threadpool; st_threadpool *tp=NULL; void *thread_cb(void *arg){ while(1){ st_task *task = (st_task*)malloc(sizeof(st_task)); pthread_mutex_lock(&tp->threadpool_lock); while(!tp->shutdown && tp->runing_tasks_cnt <= 0){ pthread_cond_wait(&tp->set_task,&tp->threadpool_lock); } if(tp->shutdown){ pthread_mutex_unlock(&tp->threadpool_lock); free(task); pthread_exit(NULL); } if(tp->runing_tasks_cnt){ //memcpy(task,&tp->tasks[tp->taskhead++%tp->max_tasks_cnt], sizeof(st_task)); memcpy(task,&tp->tasks[tp->tasktail%tp->max_tasks_cnt],sizeof(st_task)); tp->tasktail= (tp->tasktail+1)%tp->max_tasks_cnt; --(tp->runing_tasks_cnt); printf("tailpos:[%d] run_t:[%d]\n",tp->tasktail,tp->runing_tasks_cnt); pthread_cond_signal(&tp->empty_task); } pthread_mutex_unlock(&tp->threadpool_lock); task->task_cb(task->arg); } } void task_cb(void *){ static int i =0; printf("this is task_cb() runing %d\n",i++); } void create_threadpool(int max_tasks_cnt,int threadcnt){ tp = (st_threadpool *)malloc(sizeof(st_threadpool)); tp->max_tasks_cnt=max_tasks_cnt; tp->runing_tasks_cnt=0; tp->tasks = (st_task *)malloc(sizeof(st_task)* max_tasks_cnt); tp->taskhead=0; tp->tasktail=0; tp->threadcnt=threadcnt; tp->threads = (pthread_t *)malloc(sizeof(pthread_t)*threadcnt); tp->shutdown=0; pthread_mutex_init(&tp->threadpool_lock,NULL); pthread_cond_init(&tp->empty_task,NULL); pthread_cond_init(&tp->set_task,NULL); for (int i = 0; i < threadcnt; ++i) { pthread_create(&tp->threads[i],NULL,thread_cb,tp); pthread_detach(tp->threads[i]); } } void add_task(){ pthread_mutex_lock(&tp->threadpool_lock); while(tp->runing_tasks_cnt>=tp->max_tasks_cnt){ pthread_cond_wait(&tp->empty_task,&tp->threadpool_lock); } tp->tasks[tp->taskhead].arg = (void*)&tp->tasks[tp->tasktail]; tp->tasks[tp->taskhead].task_cb = task_cb; tp->taskhead = (tp->taskhead+1)%tp->max_tasks_cnt; ++(tp->runing_tasks_cnt); printf("headpos:[%d] run_t:[%d]\n",tp->taskhead,tp->runing_tasks_cnt); pthread_cond_signal(&tp->set_task); sleep(1); pthread_mutex_unlock(&tp->threadpool_lock); } void destroy_threadpool(){ tp->shutdown=1; pthread_cond_broadcast(&tp->set_task); pthread_mutex_destroy(&tp->threadpool_lock); pthread_cond_destroy(&tp->set_task); pthread_cond_destroy(&tp->empty_task); free(tp->threads); free(tp->tasks); free(tp); } int main (){ create_threadpool(10,4); for (int i = 0; i < 30; ++i) { add_task(); } printf("end\n"); sleep(100); //destroy_threadpool(); }
gcc threadpool.c -o tp -lpthread
伪代码:
数据结构:
- 线程池:任务队列(循环队列),线程队列,shutdown标记,线程池锁,消费者条件变量,生产者条件变量。
- 任务:执行函数,函数参数
逻辑
- 初始化任务队列,线程数组,shutdown标记,线程池锁,消费者条件变量,生产者条件变量。创建线程(阻塞在生产者的条件变量)。
- 线程池添加任务
给线程池枷锁
若任务队列为满,阻塞在消费者条件变量,直到消费者唤醒,重新执行这行逻辑。
cpy任务队列的当前任务,调整任务队列,向生产者条件变量发送信号。
线程池解锁
- 线程执行
被生产者唤醒,给线程池枷锁
若shutdown!=1且任务队列为空,阻塞在生产者条件变量,直到被生产者唤醒,重新执行这行逻辑。
任务队列去任务,调整任务队列,向消费者条件变量发送信号。
线程池解锁
执行任务