c++简单线程池实现
线程池,简单来说就是有一堆已经创建好的线程(最大数目一定),初始时他们都处于空闲状态,当有新的任务进来,从线程池中取出一个空闲的线程处理任务,然后当任务处理完成之后,该线程被重新放回到线程池中,供其他的任务使用,当线程池中的线程都在处理任务时,就没有空闲线程供使用,此时,若有新的任务产生,只能等待线程池中有线程结束任务空闲才能执行,下面是线程池的工作原理图:

我们为什么要使用线程池呢?
简单来说就是线程本身存在开销,我们利用多线程来进行任务处理,单线程也不能滥用,无止禁的开新线程会给系统产生大量消耗,而线程本来就是可重用的资源,不需要每次使用时都进行初始化,因此可以采用有限的线程个数处理无限的任务。
废话少说,直接上代码
首先是用条件变量和互斥量封装的一个状态,用于保护线程池的状态
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_timedwait(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.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 ;
} //加锁
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_timedwait(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 ;
}
然后是线程池对应的threadpool.h和threadpool.c
#ifndef _THREAD_POOL_H_
#define _THREAD_POOL_H_ //线程池头文件 #include "condition.h" //封装线程池中的对象需要执行的任务对象
typedef struct task
{
void *(*run)(void *args); //函数指针,需要执行的任务
void *arg; //参数
struct task *next; //任务队列中下一个任务
}task_t; //下面是线程池结构体
typedef struct threadpool
{
condition_t ready; //状态量
task_t *first; //任务队列中第一个任务
task_t *last; //任务队列中最后一个任务
int counter; //线程池中已有线程数
int idle; //线程池中kongxi线程数
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
#include "threadpool.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <time.h> //创建的线程执行
void *thread_routine(void *arg)
{
struct timespec abstime;
int timeout;
printf("thread %d is starting\n", (int)pthread_self());
threadpool_t *pool = (threadpool_t *)arg;
while()
{
timeout = ;
//访问线程池之前需要加锁
condition_lock(&pool->ready);
//空闲
pool->idle++;
//等待队列有任务到来 或者 收到线程池销毁通知
while(pool->first == NULL && !pool->quit)
{
//否则线程阻塞等待
printf("thread %d is waiting\n", (int)pthread_self());
//获取从当前时间,并加上等待时间, 设置进程的超时睡眠时间
clock_gettime(CLOCK_REALTIME, &abstime);
abstime.tv_sec += ;
int status;
status = condition_timedwait(&pool->ready, &abstime); //该函数会解锁,允许其他线程访问,当被唤醒时,加锁
if(status == ETIMEDOUT)
{
printf("thread %d wait timed out\n", (int)pthread_self());
timeout = ;
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--;//当前工作的线程数-1
//若线程池中没有线程,通知等待线程(主线程)全部任务已经完成
if(pool->counter == )
{
condition_signal(&pool->ready);
}
condition_unlock(&pool->ready);
break;
}
//超时,跳出销毁线程
if(timeout == )
{
pool->counter--;//当前工作的线程数-1
condition_unlock(&pool->ready);
break;
} condition_unlock(&pool->ready);
} printf("thread %d 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 =;
pool->idle =;
pool->max_threads = threads;
pool->quit =; } //增加一个任务到线程池
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 > )
{
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);
//设置销毁标记为1
pool->quit = ;
//线程池中线程个数大于0
if(pool->counter > )
{
//对于等待的线程,发送信号唤醒
if(pool->idle > )
{
condition_broadcast(&pool->ready);
}
//正在执行任务的线程,等待他们结束任务
while(pool->counter)
{
condition_wait(&pool->ready);
}
}
condition_unlock(&pool->ready);
condition_destroy(&pool->ready);
}
测试代码:
#include "threadpool.h"
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h> void* mytask(void *arg)
{
printf("thread %d is working on task %d\n", (int)pthread_self(), *(int*)arg);
sleep();
free(arg);
return NULL;
} //测试代码
int main(void)
{
threadpool_t pool;
//初始化线程池,最多三个线程
threadpool_init(&pool, );
int i;
//创建十个任务
for(i=; i < ; i++)
{
int *arg = malloc(sizeof(int));
*arg = i;
threadpool_add_task(&pool, mytask, arg); }
threadpool_destroy(&pool);
return ;
}
输出结果:

可以看出程序先后创建了三个线程进行工作,当没有任务空闲时,等待2s直接退出销毁线程
c++简单线程池实现的更多相关文章
- Linux多线程实践(9) --简单线程池的设计与实现
线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以 ...
- Linux下简单线程池的实现
大多数的网络服务器,包括Web服务器都具有一个特点,就是单位时间内必须处理数目巨大的连接请求,但是处理时间却是比较短的.在传统的多线程服务器模型中是这样实现的:一旦有个服务请求到达,就创建一个新的服务 ...
- 基于C++11的100行实现简单线程池
基于C++11的100行实现简单线程池 1 线程池原理 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小, ...
- C++11的简单线程池代码阅读
这是一个简单的C++11实现的线程池,代码很简单. 原理就是管理一个任务队列和一个工作线程队列. 工作线程不断的从任务队列取任务,然后执行.如果没有任务就等待新任务的到来.添加新任务的时候先添加到任务 ...
- C语言实现简单线程池(转-Newerth)
有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带来的开销,我们可以使用线程池.下面是一个C语言实现的简单的线程池. 头文件: 1: #ifndef THREAD_POOL ...
- LINUX下的简单线程池
前言 任何一种设计方式的引入都会带来额外的开支,是否使用,取决于能带来多大的好处和能带来多大的坏处,好处与坏处包括程序的性能.代码的可读性.代码的可维护性.程序的开发效率等. 线程池适用场合:任务比较 ...
- 基于Linux/C++简单线程池的实现
我们知道Java语言对于多线程的支持十分丰富,JDK本身提供了很多性能优良的库,包括ThreadPoolExecutor和ScheduleThreadPoolExecutor等.C++11中的STL也 ...
- c++简单线程池实现(转)
线程池,简单来说就是有一堆已经创建好的线程(最大数目一定),初始时他们都处于空闲状态,当有新的任务进来,从线程池中取出一个空闲的线程处理任务,然后当任务处理完成之后,该线程被重新放回到线程池中,供其他 ...
- linux下c语言实现简单----线程池
这两天刚好看完linux&c这本书的进程线程部分,学长建议可以用c语言实现一个简单的线程池,也是对线程知识的一个回顾与应用.线程的优点有好多,它是"轻量级的进程",所需资源 ...
随机推荐
- redis客户端可以连接集群,但JedisCluster连接redis集群一直报Could not get a resource from the pool
一,问题描述: (如题目)通过jedis连接redis单机成功,使用JedisCluster连接redis集群一直报Could not get a resource from the pool 但是使 ...
- 线程池与Python中的GIL
线程池是一个操作系统的概念,它是对多线程的一种优化. 多线程的时候,创建和销毁线程伴随着操作系统的开销,如果频繁创建/销毁线程,则会使效率大大降低. 而线程池,是先创建出一批线程放入池子里,需要创建线 ...
- 在CentOS7.1上安装Gitlab碰到的问题及解决方法
一 前言 关于在CentOS7上安装Gitlab, 官方文档已经很详细了,步骤大家按照官方的安装文档一步一步安装即可, 这里就不在累述.官方安装文档地址: https://about.gitlab. ...
- 2018.3.28html学习笔记
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> ...
- 2017-2018-1 Java演绎法 第三周 作业
团队任务:团队展示与选题 团队展示 队员学号及姓名 学号 姓名 主要负责工作 20162315 马军 日常统计,项目部分代码 20162316 刘诚昊 项目部分代码,代码质量测试 20162317 袁 ...
- 关于5303狄惟佳同学的myod程序设计的补充实现
关于5303狄惟佳同学的myod程序设计的补充实现 原版代码实现的局限 原版代码主函数 int main(int argc,char *argv[]) { if(strcmp(argv[1], &qu ...
- C程序第二次作业
2-1删除字符串中数字字符 1.设计思路 (1)主要描述题目算法 第一步:遍历指针s所指的s数组. 第二步:如果 * (s+i)在0至9之间的话,则跳过此 * (s+i). 第三步:如果* (s+i) ...
- Linux中Eclipse下搭建Web开发环境
0. 准备工作 java环境,Linux下基本上都有含开源jdk的库,可直接下载,且不用配置环境变量,当然也可以官网下载后自己配置: Eclipse Neon,注意看清是64位还是32位,下载的应该是 ...
- cpp常用函数总结
//sprintf sprintf(temp_str_result, "%lf", temp_double); result = temp_str_result; (*begin) ...
- python的Flask 介绍
Flask 介绍 知识点 微框架.WSGI.模板引擎概念 使用 Flask 做 web 应用 模板的使用 根据 URL 返回特定网页 实验步骤 1. 什么是 Flask? Flask 是一个 web ...