第四十一章 一个简单线程池的实现
线程池的作用
- 用于执行大量相对短暂的任务
- 计算密集型任务 线程 = CPU个数
- I/O密集型任务 线程 > CPU个数
- 当任务增加的时候能够动态的增加线程池中线程的数量直到达到一个阈值
- 当任务执行完毕的时候,能够动态的销毁线程池中的线程
- 该线程池的实现本质上也是生产者与消费者模型的应用。生产者线程向任务队列中添加任务,一旦队列有任务到来,如果有等待线程就唤醒来执行任务,如果没有等待线程来且线程没有达到阈值,就创建新线程来执行任务
condition.h
#ifndef _CONDITION_H_
#define _CONDITION_H_
#include <pthread.h>
typedef struct condition
{
pthread_mutex_t pmutex;
pthread_cond_t pcond;
}condition_t;
int condition_init(condition_t *cond);
int condition_lock(condition_t *cond);
int condition_unlock(condition_t *cond);
int condition_wait(condition_t *cond);
int condition_timewait(condition_t *cond, const struct timespec *abstime);
int condition_signal(condition_t *cond);
int condition_broadcast(condition_t *cond);
int condition_destroy(condition_t *cond);
#endif // !_CONDITION_H_
condition.c
#include "condition.h"
int condition_init(condition_t *cond)
{
int status;
if((status = pthread_mutex_init(&cond->pmutex, NULL)))
return status;
if((status = pthread_cond_init(&cond->pcond, NULL)))
return status;
return 0;
}
int condition_lock(condition_t *cond)
{
return pthread_mutex_lock(&cond->pmutex);
}
int condition_unlock(condition_t *cond)
{
return pthread_mutex_unlock(&cond->pmutex);
}
int condition_wait(condition_t *cond)
{
return pthread_cond_wait(&cond->pcond, &cond->pmutex);
}
int condition_timewait(condition_t *cond, const struct timespec *abstime)
{
return pthread_cond_timedwait(&cond->pcond, &cond->pmutex, abstime);
}
int condition_signal(condition_t *cond)
{
return pthread_cond_signal(&cond->pcond);
}
int condition_broadcast(condition_t *cond)
{
return pthread_cond_broadcast(&cond->pcond);
}
int condition_destroy(condition_t *cond)
{
int status;
if((status = pthread_mutex_destroy(&cond->pmutex)))
return status;
if((status = pthread_cond_destroy(&cond->pcond)))
return status;
return 0;
}
threadpool.h
#include "condition.h"
//任务结构体,将任务放入队列由线程池中的线程来执行
typedef struct task
{
void* (*run)(void *arg); //任务回调函数
void *arg; //回调函数参数
struct task *next;
}task_t;
//线程池结构体
typedef struct threadpool
{
condition_t ready; //任务准备就绪或者线程池销毁通知
task_t *first; //任务队列头指针
task_t *last; //任务队列尾指针
int counter; //线程池中当前线程数
int idle; //线程池中当前正在等待任务的线程数
int max_threads; //线程池中最大允许的线程数
int quit; //销毁线程池的时候置1
}threadpool_t;
//初始化线程池
void threadpool_init(threadpool_t *pool, int threads);
//往线程池中添加任务
void threadpool_add_task(threadpool_t *pool, void*(*run)(void *arg), void *arg);
//销毁线程池
void threadpool_destroy(threadpool_t *pool);
threadpool.c
#include "threadpool.h"
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
void threadpool_init(threadpool_t *pool, int threads)
{
//初始化pool结构体
condition_init(&pool->ready);
pool->first = NULL;
pool->last = NULL;
pool->counter = 0;
pool->idle = 0;
pool->max_threads = threads;
pool->quit = 0;
}
void* thread_toutine(void* arg)
{
int timeout;
struct timespec abstime;
printf("thread 0x%0x is starting\n", (int)pthread_self());
threadpool_t *pool = (threadpool_t*)arg;
while(1)
{
condition_lock(&pool->ready);
timeout = 0;
//未等待到条件,等待任务的线程数加1
pool->idle++;
//等待队列有任务到来或者线程池销毁通知
while(pool->first == NULL && !pool->quit)
{
printf("thread 0x%0x is waiting \n", (int)pthread_self());
//condition_wait(&pool->ready);
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += 10;
int status = condition_timewait(&pool->ready, &abstime);
if(status == ETIMEDOUT)
{
printf("thread 0x%0x is wait time out \n", (int)pthread_self());
timeout = 1;
break;
}
}
// 等待到条件,等待任务的线程数减1
pool->idle--;
// 等待到任务
if(pool->first != NULL)
{
//从对头取出任务
task_t *t = pool->first;
pool->first = t->next;
//执行任务需要一定的时间,所以要先解锁,以便生产者进程
//能够往队列中添加任务,其他消费者线程能够进入等待任务
condition_unlock(&pool->ready);
t->run(t->arg);
free(t);
condition_lock(&pool->ready);
}
// 如果等待到线程池销毁通知 且 任务队列中没有任务
if(pool->quit && pool->first == NULL)
{
pool->counter--;
if(pool->counter == 0)
condition_signal(&pool->ready);
condition_unlock(&pool->ready);
break;
}
//超时 且 任务队列中没有任务
if(timeout && pool->first == NULL)
{
pool->counter--;
condition_unlock(&pool->ready);
break;
}
condition_unlock(&pool->ready);
}
printf("thread 0x%0x is exit...\n",(int)pthread_self());
return NULL;
}
void threadpool_add_task(threadpool_t *pool, void*(*run)(void *arg), void *arg)
{
//生成新任务
task_t *newTask = (task_t*)malloc(sizeof(task_t));
newTask->run = run;
newTask->arg = arg;
newTask->next = NULL;
condition_lock(&pool->ready);
//将任务添加到队列
if(pool->first == NULL)
{
pool->first = newTask;
}
else
pool->last->next = newTask;
pool->last = newTask;
//如果有等待线程,则唤醒其中一个执行任务
if(pool->idle > 0)
{
printf("wait thread count : %d\n",pool->idle);
condition_signal(&pool->ready);
}
//没有等待线程,并且当前线程数不超过最大线程数,则创建一个新线程
else if(pool->counter < pool->max_threads)
{
pthread_t tid;
pthread_create(&tid, NULL, thread_toutine, pool);
pool->counter++;
}
condition_unlock(&pool->ready);
}
void threadpool_destroy(threadpool_t *pool)
{
if(pool->quit)
{
return;
}
condition_lock(&pool->ready);
pool->quit = 1;
if(pool->counter > 0)
{
//处于等待中的线程
if(pool->idle > 0)
condition_broadcast(&pool->ready);
//处于工作中的线程,不会受到广播
//线程池需要等待执行任务状态中的线程全部退出
while(pool->counter > 0)
condition_wait(&pool->ready);
}
condition_unlock(&pool->ready);
condition_destroy(&pool->ready);
}
main.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include "threadpool.h"
void* mytask(void* arg)
{
printf("thread 0x%0x working on task %d\n",(int)pthread_self(), *((int*)arg));
sleep(5);
free(arg);
return NULL;
}
void* mytask1(void* arg)
{
printf("thread 0x%0x working on task %d\n",(int)pthread_self(), *((int*)arg));
sleep(1);
free(arg);
return NULL;
}
int main(int argc, char* argv[])
{
threadpool_t pool;
threadpool_init(&pool, 2);
int i;
for(i=0; i<4; ++i)
{
int *arg = (int*)malloc(sizeof(int));
*arg = i;
threadpool_add_task(&pool, mytask, arg);
}
sleep(30);
threadpool_destroy(&pool);
return 0;
}
Makefile
.PHONY: all clean
CC:=gcc
CFLAGS += -Wall -g
BIN=main
all:$(BIN)
OBJ1 = main.o condition.o threadpool.o
main:${OBJ1}
$(CC) $(CFLAGS) $^ -o $@ -lpthread
%.o:%.c
$(CC) $(CFLAGS) -c $< -o $@
clean:
rm -rf $(BIN)
cleanall:
rm -rf $(BIN) $(OBJ1)