1. 概念
- 为什么使用线程池?
频繁创建和销毁线程浪费CPU资源 - 线程是什么?
一堆线程放在一个池子里统一管理
2. 构成
2.1 任务队列job_queue
- 作用
存放待处理的任务 - 成员
No. | 构成 | 接口 |
---|---|---|
1 | 处理函数 | void *(*)(void*) |
2 | 参数 | void *arg |
3 | 队列指针 | struct job_queue* pnext |
2.2 工作线程worker
- 作用
处理任务
2.3 线程池thread_pool
作用
管理多个线程并提供任务队列的接口成员
No. | 构成 | 接口 |
---|---|---|
1 | 初始化 | threadpool_init() |
2 | 销毁 | threadpool_destroy() |
3 | 添加任务 | threadpool_add_job() |
3. 流程
使用流程
- 初始化线程池
- 向线程池添加任务
- 销毁线程池
线程池初始化
- 初始化任务队列和工作线程组
- 将等候在条件变量(任务队列上有任务)上的一个线程唤醒并从该任务队列中取出第一个任务给该线程执行
- 等待任务队列中所有任务执行完毕
4. 实例
- Linux C语言实现
#include
#include
#include
#include
struct job_queue{
void* (*func)(void* arg);
void* arg;
struct job_queue* pnext;
};
struct threadpool{
struct job_queue* phead;
struct job_queue* ptail;
pthread_t* pworks;
size_t nthread;
pthread_mutex_t mutex;
pthread_cond_t cond;
int destroy;
};
void* threadpool_routine(void* arg){
assert(NULL != arg);
struct threadpool* pthpool = (struct threadpool*)arg;
for(;;){
struct job_queue* pjob = NULL;
pthread_mutex_lock(&(pthpool->mutex));
while(pthpool->phead == NULL && 0 == pthpool->destroy){
pthread_cond_wait(&(pthpool->cond),&(pthpool->mutex));
}
//
if(1 == pthpool->destroy){
printf("%lu exit\n",pthread_self());
pthread_mutex_unlock(&(pthpool->mutex));
pthread_exit(NULL);
}
pjob = pthpool->phead;
pthpool->phead = pjob->pnext;
pthread_mutex_unlock(&(pthpool->mutex));
pjob->func(pjob->arg);
free(pjob);
}
}
struct threadpool* threadpool_init(size_t nthread){
struct threadpool* pthpool = malloc(sizeof(struct threadpool));
pthread_mutex_init(&(pthpool->mutex),NULL);
pthread_cond_init(&(pthpool->cond),NULL);
pthpool->phead = NULL;
pthpool->ptail = NULL;
pthpool->nthread = nthread;
pthpool->destroy = 0;
// 初始化工作线程组
pthpool->pworks = malloc(nthread * sizeof(pthread_t));
int i;
for(i=0;ipworks[i]),NULL,threadpool_routine,pthpool);
}
return pthpool;
}
void threadpool_destroy(struct threadpool* pthpool){
assert(NULL != pthpool);
while(NULL != pthpool->phead){
struct job_queue* pnext = pthpool->phead->pnext;
free(pthpool->phead);
pthpool->phead = pnext;
}
pthpool->destroy = 1;
pthread_cond_broadcast(&(pthpool->cond));
int i;
for(i=0;inthread;i++){
pthread_join(pthpool->pworks[i],NULL);
}
free(pthpool->pworks);
free(pthpool);
pthread_mutex_destroy(&(pthpool->mutex));
pthread_cond_destroy(&(pthpool->cond));
pthpool = NULL;
}
void threadpool_add_job(struct threadpool* pthpool,void*(*func)(void*),void* arg){
assert(NULL != pthpool);
struct job_queue* jq = malloc(sizeof(struct job_queue));
jq->func = func;
jq->arg = arg;
jq->pnext = NULL;
printf("add job %d\n",(int) arg);
pthread_mutex_lock(&(pthpool->mutex));
if(pthpool->phead == NULL){
pthpool->phead = jq;
pthpool->ptail = jq;
}else{
pthpool->ptail->pnext = jq;
pthpool->ptail = jq;
}
pthread_mutex_unlock(&(pthpool->mutex));
pthread_cond_signal(&(pthpool->cond));
}
void* test(void* arg){
printf("%lu do job %d\n",pthread_self(),(int)arg);
sleep(1);
}
int main(int argc,char* argv[]){
if(3 != argc){
printf("usage:%s\n <#nthread> <#njob>", argv[0]);
return 1;
}
int nthread = atoi(argv[1]);
int njob = atoi(argv[2]);
// 1. 初始化线程池
struct threadpool* pool = threadpool_init(nthread);
// 2. 向线程池添加任务
int i;
for(i=0;i
注意:任务队列初始化在工作线程组前。
- Linux C++98实现
#include
#include
#include
#include
#include
#include
using namespace std;
class ThreadPool{
typedef void (*func_t)(int);
public:
ThreadPool(size_t count):destroy(false){
// 初始化互斥锁和条件变量
pthread_mutex_init(&mutex,NULL);
pthread_cond_init(&cond,NULL);
// 初始化线程组
for(int i=0;i(&ThreadPool::Route),this);
threads.push_back(tid);
}
}
~ThreadPool(){
// 通知线程退出
destroy = true;
pthread_cond_broadcast(&cond);
for(vector::iterator it = threads.begin();it != threads.end();it++){
pthread_join(*it,NULL);
}
// 销毁互斥锁和条件变量
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
}
void AddJob(func_t func,int arg){
pthread_mutex_lock(&mutex);
tasks.push(func);
args.push(arg);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
private:
static void Route(ThreadPool* pPool){
for(;;){
pthread_mutex_lock(&(pPool->mutex));
// 如果没有任务等待
while(pPool->tasks.empty() && !pPool->destroy){
pthread_cond_wait(&(pPool->cond),&(pPool->mutex));
}
// 线程退出
if(pPool->destroy){
pthread_mutex_unlock(&(pPool->mutex));
break;
}
// 获取任务
func_t task = pPool->tasks.front();
pPool->tasks.pop();
int arg = pPool->args.front();
pPool->args.pop();
pthread_mutex_unlock(&(pPool->mutex));
// 执行任务
task(arg);
}
}
private:
vector threads; ///< 线程组
queue tasks; ///< 任务队列
queue args; ///< 参数队列
pthread_mutex_t mutex;
pthread_cond_t cond;
bool destroy; ///< 线程池销毁标志
};
void test(int arg){
printf("%lu do job %d\n",pthread_self(),arg);
sleep(1);
}
int main(int argc,char** argv){
if(3 != argc){
printf("usage:%s\n <#nthread> <#njob>", argv[0]);
return 1;
}
// 1. 初始化线程池
int nthread = atoi(argv[1]);
int njob = atoi(argv[2]);
ThreadPool pool(nthread);
// 2. 向线程池添加任务
for(int i=0;i
- C++11实现
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
class ThreadPool{
typedef function func_t;
public:
ThreadPool(size_t count):destroy(false){
// 初始化线程组
for(int i=0;i lck(pPool->mtx);
// 如果没有任务等待
while(pPool->tasks.empty() && !pPool->destroy){
pPool->cond.wait(lck);
}
// 线程退出
if(pPool->destroy){
break;
}
// 获取任务
func_t task = pPool->tasks.front();
pPool->tasks.pop();
int arg = pPool->args.front();
pPool->args.pop();
lck.unlock();
// 执行任务
task(arg);
}
}
private:
vector threads; ///< 线程组
queue tasks; ///< 任务队列
queue args; ///< 参数队列
mutex mtx;
condition_variable cond;
bool destroy; ///< 线程池销毁标志
};
void test(int arg){
cout << this_thread::get_id() << " do job " << arg << endl;
this_thread::sleep_for(chrono::seconds(1));
}
int main(int argc,char** argv){
if(3 != argc){
printf("usage:%s\n <#nthread> <#njob>", argv[0]);
return 1;
}
// 1. 初始化线程池
int nthread = atoi(argv[1]);
int njob = atoi(argv[2]);
ThreadPool pool(nthread);
// 2. 向线程池添加任务
for(int i=0;i
C++11 lambda表达式实现
#include
#include
#include
#include
#include
#include
#include
using namespace std;
class ThreadPool{
vector threads;
queue> tasks;
condition_variable cond;
mutex m;
bool exited = false;
public:
ThreadPool(int num){
auto routine = [this](){
while(true){
unique_lock lock(m);
while(tasks.empty() && !exited) cond.wait(lock);
if(exited) break;
auto func = tasks.front();
tasks.pop();
lock.unlock();
func();
}
};
for(int i=0;i func){
lock_guard guard(m);
tasks.push(func);
cond.notify_one();
// signal
}
};
int main(){
mutex m;
auto test = [&m](){
this_thread::sleep_for(2s);
lock_guard guard(m);
cout << this_thread::get_id() << " do something..." << endl;
};
ThreadPool pool(5);
for(int i=0;i<15;++i){
pool.AddTask(test);
}
this_thread::sleep_for(10s);
}