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

我们为什么要使用线程池呢?

简单来说就是线程本身存在开销,我们利用多线程来进行任务处理,单线程也不能滥用,无止禁的开新线程会给系统产生大量消耗,而线程本来就是可重用的资源,不需要每次使用时都进行初始化,因此可以采用有限的线程个数处理无限的任务。

废话少说,直接上代码

首先是用条件变量和互斥量封装的一个状态,用于保护线程池的状态

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++简单线程池实现的更多相关文章

  1. Linux多线程实践(9) --简单线程池的设计与实现

    线程池的技术背景 在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源.在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收.所以 ...

  2. Linux下简单线程池的实现

    大多数的网络服务器,包括Web服务器都具有一个特点,就是单位时间内必须处理数目巨大的连接请求,但是处理时间却是比较短的.在传统的多线程服务器模型中是这样实现的:一旦有个服务请求到达,就创建一个新的服务 ...

  3. 基于C++11的100行实现简单线程池

    基于C++11的100行实现简单线程池 1 线程池原理 线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务.线程池线程都是后台线程.每个线程都使用默认的堆栈大小, ...

  4. C++11的简单线程池代码阅读

    这是一个简单的C++11实现的线程池,代码很简单. 原理就是管理一个任务队列和一个工作线程队列. 工作线程不断的从任务队列取任务,然后执行.如果没有任务就等待新任务的到来.添加新任务的时候先添加到任务 ...

  5. C语言实现简单线程池(转-Newerth)

    有时我们会需要大量线程来处理一些相互独立的任务,为了避免频繁的申请释放线程所带来的开销,我们可以使用线程池.下面是一个C语言实现的简单的线程池. 头文件: 1: #ifndef THREAD_POOL ...

  6. LINUX下的简单线程池

    前言 任何一种设计方式的引入都会带来额外的开支,是否使用,取决于能带来多大的好处和能带来多大的坏处,好处与坏处包括程序的性能.代码的可读性.代码的可维护性.程序的开发效率等. 线程池适用场合:任务比较 ...

  7. 基于Linux/C++简单线程池的实现

    我们知道Java语言对于多线程的支持十分丰富,JDK本身提供了很多性能优良的库,包括ThreadPoolExecutor和ScheduleThreadPoolExecutor等.C++11中的STL也 ...

  8. c++简单线程池实现(转)

    线程池,简单来说就是有一堆已经创建好的线程(最大数目一定),初始时他们都处于空闲状态,当有新的任务进来,从线程池中取出一个空闲的线程处理任务,然后当任务处理完成之后,该线程被重新放回到线程池中,供其他 ...

  9. linux下c语言实现简单----线程池

    这两天刚好看完linux&c这本书的进程线程部分,学长建议可以用c语言实现一个简单的线程池,也是对线程知识的一个回顾与应用.线程的优点有好多,它是"轻量级的进程",所需资源 ...

随机推荐

  1. 如何测试一个WEB的输入框?

    WEB输入框是B/S架构系统中页面使用非常频繁的控件,比如我们登录一个网站,输入 用户名和密码的控件都是输入框,比如使用百度搜索,在输入搜索内容的控件也是输入框,比如网购一个物品,我们需要输入购买的数 ...

  2. Vue基础

    1.可以使用 methods 来替代 computed,效果上两个都是一样的. 但是 computed 是基于它的依赖缓存,只有相关依赖发生改变时才会重新取值. {{ reversedMessage ...

  3. Jquery判断单选框是否选中和获取选中的值

    第一种:利用选中值判断选中 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http ...

  4. 算法题丨Longest Consecutive Sequence

    描述 Given an unsorted array of integers, find the length of the longest consecutive elements sequence ...

  5. mongodb 集群分片

    分片 在Mongodb里面存在另一种集群,就是分片技术,可以满足MongoDB数据量大量增长的需求 当MongoDB存储海量的数据时,一台机器可能不足以存储数据,也可能不足以提供可接受的读写吞吐量,这 ...

  6. JAVA中最容易让人忽视的基础。

    可能很多找编程工作的人在面试的时候都有这种感受,去到一个公司填写面试试题的时候,多数人往往死在比较基础的知识点上.不要奇怪,事实就是如此一般来说,大多数公司给出的基础题大概有122道,代码题19道左右 ...

  7. centos 安装配置 mysql

    安装环境:CentOS7 64位 MINI版,安装MySQL5.7 1.配置YUM源 在MySQL官网中下载YUM源rpm安装包:http://dev.mysql.com/downloads/repo ...

  8. 【nodejs】安装browser-sync 遇到错误提示

    首先我用的是mac电脑在我执行安装browser-sync时遇到如下问题: 因为不被允许所以我只能不安装全局了: 但是又出现了如下的新问题 纠结了半个小时,终于知道为什么会出现这个问题了, node只 ...

  9. 使用 PHP 来做 Vue.js 的 SSR 服务端渲染

    对于客户端应用来说,服务端渲染是一个热门话题.然而不幸的是,这并不是一件容易的事,尤其是对于不用 Node.js 环境开发的人来说. 我发布了两个库让 PHP 从服务端渲染成为可能.spatie/se ...

  10. 0基础菜鸟学前端之Vue.js

    简介:0基础前端菜鸟,啃了将近半月前端VUE框架,对前端知识有了初步的了解.下面总结一下这段时间的学习心得. 文章结构 前端基础 Vue.js简介 Vue.js常用指令 Vue.js组件 Vue.js ...