1.线程池说明
- 线程池拥有若干个线程
- 用于执行大量相对短暂的任务
由于线程个数小于任务的数量,因而任务需要进入队列中进行等待,在短时间可以得到一个线程对任务进行处理
- 线程的个数与任务的类型有关
(1)计算密集型任务: 执行任务时很少被阻塞,线程个数=CPU个数(并发数是确定的),线程数过多,会导致线程上下文切换,降低效率
(2)I/O密集型任务: 执行任务时,可能会被I/O中断,即线程被挂起,所以线程个数>CPU个数,若线程少了,刚好又都被挂起,当有新任务来了,无法处理任务了
- 当任务增加的时候能够动态的增加线程池中线程的数量直到达到一个阈值
当任务执行完毕的时候,能够动态的销毁线程池中的线程
- 该线程池的实现本质上也是生产者与消费者模型的应用。
生产者线程向任务队列中添加任务,一旦队列有任务到来,如果有等待线程就唤醒来执行任务,如果没有等待线程并且线程数没有达到阈值,就创建新线程来执行任务。
2.线程池实现
- 测试驱动开发,先将数据结构写好,再写接口,然后make一下看是否报错,最后再写实现
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;
} 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);
- eg:线程池的实现
NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\threadpool.h
NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\threadpool.c
========================NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\threadpool.h========
#ifndef NETWORKPROGRAMMING_THREADPOOL_H
#define NETWORKPROGRAMMING_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;
} 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);
#endif
======NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\threadpool.c==========
#include "threadpool.h"
#include <pthread.h>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
void *thread_routine (void *arg)
{
struct timespec abstime;
int timeout;
printf("thread 0x%x is starting\n", (int)pthread_self());
threadpool_t *pool = (threadpool_t*)arg;
while (1)
{
timeout = 0;
condition_lock(&pool->ready);
pool->idle++;
while (pool->first == NULL && !pool->quit)
{
printf("thread 0x%x is waiting\n", (int)pthread_self());
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += 2;
int state = condition_timewait(&pool->ready, &abstime);
if (state == ETIMEDOUT)
{
printf("thread 0x%x is wait time out\n", (int)pthread_self());
timeout = 1;
break;
}
}
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%x is exiting \n", (int)pthread_self());
return NULL;
}
void threadpool_init(threadpool_t *pool, int threads)
{
condition_init(&(pool->ready));
pool->first = NULL;
pool->last = NULL;
pool->counter = 0;
pool->idle = 0;
pool->max_threads = threads;
pool->quit = 0;
}
void threadpool_add_task(threadpool_t *pool, void *(*run)(void *arg), void *arg)
{
void *(*run)(void *arg);
void *arg;
struct task* next;
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)
{
condition_signal(&pool->ready);
}
else if (pool->counter < pool->max_threads)
{
pthread_t tid;
pthread_create(&tid, NULL, thread_routine, 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);
}
- eg:线程池的条件变量和互斥量的封装
NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\condition.h
NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\condition.c
===============NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\condition.h==================
#ifndef NETWORKPROGRAMMING_CONDITION_H
#define NETWORKPROGRAMMING_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
===================NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\condition.c====================
#include "condition.h"
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <iostream>
using namespace std;
int condition_init(condition_t *cond)
{
int state;
state = pthread_cond_init(&(cond->pcond), NULL);
if (state == 0)
{
return state;
}
state = pthread_mutex_init(&(cond->pmutex), NULL);
if (state == 0)
{
return state;
}
return 0;
}
int condition_lock(condition_t *cond)
{
if (pthread_mutex_lock(&(cond->pmutex)) == 0)
{
printf("pthread_mutex_lock error\n");
exit(EXIT_FAILURE);
}
return 1;
}
int condition_unlock(condition_t *cond)
{
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 state;
state = pthread_cond_destroy(&(cond->pcond));
if (state == 0)
{
return state;
}
state = pthread_mutex_destroy(&(cond->pmutex));
if (state == 0)
{
return state;
}
return 0;
}
- NetworkProgramming-master (1)\NetworkProgramming-master\P41threadpool\test.c
#include "condition.h"
#include "threadpool.h"
#include <iostream>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
void *run (void *arg)
{
printf("threadpool 0x%x working task %d\n", (int)pthread_self(), *(int*)(arg));
sleep(1);
free(arg);
return NULL;
}
int main(void)
{
threadpool_t pool;
threadpool_init(&pool, 3);
int i;
for (i = 0; i < 10; ++i)
{
int *a = (int*)malloc(sizeof(int));
*a = i;
threadpool_add_task(&pool, run, a);
}
threadpool_destroy(&pool);
return 0;
}
- 测试结果:
若将下面的代码屏蔽,程序则无法销毁
if (pool->counter == 0)
{
condition_signal(&pool->ready);
}
.PHONY:clean
CC=gcc
CFLAGS=-Wall -g
ALL=main
OBJS=threadpool.o main.o condition.o
all:$(ALL)
%.o:%.c
$(cc) $(CFLAGS) -c $< -o $@
main:$(OBJS)
$(cc) $(CFLAGS) $^ -o $@ -lpthread -lrt
clean:
rm -f $(ALL) *.o