线程池:
当需要大量的并且是相对短暂的线程,我们需要创建线程池。
计算密集型: 线程池中的线程个数应该等于(=) CPU。
IO密集型: 线程池中的线程个数大于(>)CPU。
目的:
能够动态的增加线程池中的线程个数;
动态的销毁线程池中的线程.
本质:
是一个生产者消费者模型,来了任务放到任务队列,线程池中的线程从任务队列中拿任务,然后进行处理。
代码实现:
Makefile test.c threadpool.h threadpool.c condition.c condition.h
Makefile :
.PHONY: clean
OBJETS = threadpool.o \
condition.o \
test.o
CC=gcc
all : test
test : $(OBJETS)
$(CC) $^ -o $@ -lpthread -lrt
%.O : %.c
gcc -c $< -o $@
clean:
rm -rf $(OBJETS)
conditon.h:
#ifndef __CONDITION_H__
#define __CONDITION_H__
#include <pthread.h>
#include <time.h>
typedef struct condition{
pthread_mutex_t pmutex;
pthread_cond_t pcond;
}condition_t;
int condition_init(condition_t *pc);
int condition_destroy(condition_t *pc);
int condition_lock(condition_t *pc);
int condition_unlock(condition_t *pc);
int condition_wait(condition_t *pc);
int condition_timedwait(condition_t *pc, struct timespec *abstime);
int condition_signal(condition_t *pc);
int condition_boardcast(condition_t *pc);
#endif //__CONDITION_H__
condition.c:
#include "condition.h"
int condition_init(condition_t *pc)
{
int ret = 0;
do {
ret = pthread_cond_init(&pc->pcond, NULL);
if (ret != 0 ) break;
ret = pthread_mutex_init(&pc->pmutex, NULL);
} while ( 0 );
return ret;
}
int condition_destroy(condition_t *pc)
{
int ret = 0;
do {
ret = pthread_cond_destroy(&pc->pcond);
if (ret != 0 ) break;
ret = pthread_mutex_destroy(&pc->pmutex);
} while ( 0 );
return 0;
}
int condition_lock(condition_t *pc)
{
return pthread_mutex_lock(&pc->pmutex);
}
int condition_unlock(condition_t *pc)
{
return pthread_mutex_unlock(&pc->pmutex);
}
int condition_wait(condition_t *pc)
{
return pthread_cond_wait(&pc->pcond, &pc->pmutex);
}
int condition_timedwait(condition_t *pc, struct timespec *abstime)
{
return pthread_cond_timedwait(&pc->pcond, &pc->pmutex, abstime);
}
int condition_signal(condition_t *pc)
{
return pthread_cond_signal(&pc->pcond);
}
int condition_boardcast(condition_t *pc)
{
return pthread_cond_broadcast(&pc->pcond);
}
threadpool.h :
#ifndef __THREADPOOL_H__
#define __THREADPOOL_H__
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "condition.h"
// 任务节点
typedef struct node {
void *(*pfun)(void *); // 回调函数
void *arg; // 回调函数的参数
struct node *next;
}node_t;
// 代表线程池
typedef struct threadpool {
condition_t ready; // 控制同步和互斥
node_t *first; // 队头指针
node_t *tail; // 队尾指针
int counter; // 线程池中当前有多少个线程
int idle; // 空闲线程个数
int max_thread; // 最多可以创建多少个线程
int quit; // 为1,代表要销毁线程池
}threadpool_t;
// 初始化线程池
void threadpool_init(threadpool_t *pool, int max_thread);
// 添加任务
void threadpool_add(threadpool_t *pool, void *(*pf)(void*), void *arg);
// 销毁线程池
void threadpool_destroy(threadpool_t *pool);
#endif // __THREADPOOL_H__
threadpool.c :
#include "threadpool.h"
#include <errno.h>
// 初始化线程池
void threadpool_init(threadpool_t *pool, int max_thread)
{
condition_init(&pool->ready);
pool->tail = NULL;
pool->idle = 0;
pool->quit = 0;
pool->first = NULL;
pool->counter = 0;
pool->max_thread = max_thread;
}
static void *route(void *arg)
{
threadpool_t *pool = (threadpool_t*)arg;
int timeout = 0;
while ( 1 ) {
timeout = 0;
condition_lock(&pool->ready);
pool->idle++; // 还没开始工作,是一个空闲线程
while ( pool->first == NULL && pool->quit==0) {
struct timespec abs;
clock_gettime(CLOCK_REALTIME, &abs);
abs.tv_sec += 2;
int ret = condition_timedwait(&pool->ready, &abs);
if ( ret == ETIMEDOUT ) {
timeout = 1;
break;
}
}
pool->idle--; // 开始工作,空闲线程个数减少
// 处理任务
if ( pool->first != NULL ) {
node_t *p = pool->first;
pool->first = p->next;
// 防止回调任务执行时间太长,导致别的线程没法执行
condition_unlock(&pool->ready);
(p->pfun)(p->arg);
free(p);
condition_lock(&pool->ready);
}
// 处理超时
if ( timeout == 1 && pool->first == NULL ) {
printf("%#X thread time out exit\n", pthread_self());
pool->counter--;
condition_unlock(&pool->ready);
break;
}
// 收到退出通知
if ( pool->quit == 1 && pool->first == NULL ) {
printf("%#X thread quit\n", pthread_self());
pool->counter--;
if ( pool->counter == 0 )
condition_signal(&pool->ready);
condition_unlock(&pool->ready);
break;
}
condition_unlock(&pool->ready);
}
}
// 添加任务
void threadpool_add(threadpool_t *pool, void *(*pf)(void*), void *arg)
{
// 生成任务节点
node_t *pnode = (node_t*)malloc(sizeof(node_t));
memset(pnode, 0x00, sizeof(node_t));
pnode->pfun = pf;
pnode->arg = arg;
pnode->next = NULL;
// 修改多个线程都可能修改的数据
condition_lock(&pool->ready);
// 放入任务队列
if ( pool->first == NULL )
pool->first = pnode;
else
pool->tail->next = pnode;
pool->tail = pnode;
// 如果池中有空闲线程,唤醒它执行任务
if ( pool->idle > 0 ) {
condition_signal(&pool->ready);
}
// 如果没有空闲线程,并且当前线程个数小于最大值,创建新线程来执行任务
else if ( pool->counter < pool->max_thread ) {
pthread_t tid;
pthread_create(&tid, NULL, route, (void*)pool);
pthread_detach(tid);
pool->counter ++; // 线程池中线程个数增加
}
condition_unlock(&pool->ready);
}
// 销毁线程池
void threadpool_destroy(threadpool_t *pool)
{
if ( pool->quit == 1 )
return;
condition_lock(&pool->ready);
pool->quit = 1;
if ( pool->counter > 0 ) {
while ( pool->idle > 0 )
condition_boardcast(&pool->ready);
}
// 等待没有收到销毁广播,这些线程都是正在执行任务。
while ( pool->counter > 0 ) {
condition_wait(&pool->ready);
}
condition_unlock(&pool->ready);
}
test.c :
#include "threadpool.h"
void *mytask( void *arg)
{
int id = *(int*)arg;
free(arg);
printf("%#X thread execute %d\n", pthread_self(), id);
sleep(1);
}
int main( void )
{
threadpool_t pool;
threadpool_init(&pool, 4);
for (int i=0; i<10; i++) {
int *p = malloc(sizeof(int));
*p = i;
threadpool_add(&pool, mytask, p);
}
threadpool_destroy(&pool);
}