、为什么需要线程池?

部分应用程序需要执行很多细小的任务,对于每个任务都创建一个线程来完成,任务完成后销毁线程,而这就会产生一个问题:当执行的任务所需要的时间T1小于等于创建线程时间T2和销毁线程时间T3总和时即T1 <= T2 + T3,应用处理任务的响应能力会大大减弱,从而影响了应用程序性能,为了解决这类问题,线程池技术提供了很好的解决方案。线程池顾名思义就是把线程资源池化,在应用启动时一次性创建合适数量的线程,当需要执行任务时就从线程池中分配一个已经创建好的线程来执行,执行完在把线程归还,只在应用停时再一次性销毁所有的线程。

、线程池的基本组成部分

一个简单的线程池至少包括下列的组成部分:

)线程池管理器(ThreadPool):用于创建一个线程池对象并管理线程池,如分配任务给某个空闲线程,查看当前线程状态等等的操作。

)工作线程(WorkThread):线程池中线程,可能是挂起,可能是被分配了任务,若然是挂起,则用一个信号量去阻塞直到有任务分配。

)任务接口(Task):每个任务必须实行的接口,以供工作线程调度任务执行。

、Unix下的线程池实现

将给大家展示的线程池实现的类如下,含有比较多的面向对象设计思想。
主要是
一个线程池管理多个工作线程类,每个工作线程类对象管理一个线程。

1)Mutex:互斥量类,里面只有一个pthread_mutex_t的私有成员,对POSIX互斥量进行封装,后面用于线程池的队列和栈。

Mutex.h

 #ifndef MUTEX_H
#define MUTEX_H #include <iostream>
#include <pthread.h>
using namespace std; class Mutex
{
public:
Mutex();
void Lock();
void Unlock(); private:
pthread_mutex_t mutex;
}; #endif

Mutex.cpp

 #include "Mutex.h"

 Mutex::Mutex()
{
pthread_mutex_init(&mutex,NULL);
} void Mutex::Lock()
{
pthread_mutex_lock(&mutex);
} void Mutex::Unlock()
{
pthread_mutex_unlock(&mutex);
}

2)BaseTask:任务的抽象基类,任何具体的任务都要继承该类,并实现自己的void * run()函数,
即线程运行的函数。在这里继承的类定义实现在main函数里面。抽象类不能被实例化,但可以声明为指针指向继承的子类。

BaseTask.h

 #ifndef BASE_TASK_H
#define BASE_TASK_H #include <iostream>
using namespace std; class BaseTask
{
public:
virtual void run() = ;
}; #endif

3).MyTask:具体任务类,继承了BaseTask,实现了具体任务。

MyTask.h

 #ifndef MYTASK_H
#define MYTASK_H
#include "BaseTask.h" class MyTask : public BaseTask
{
public:
virtual void run(void);
}; #endif

MyTask.cpp

  #include "MyTask.h"

  void MyTask::run(void)
{
cout<<"Hello MyTask"<<endl;
}

4).MyThread: 对POSIX线程的C++封装,实现了执行任务的基本接口

MyThread.h

 #ifndef MYTHREAD_H
#define MYTHREAD_H #include <iostream>
#include <pthread.h>
#include <semaphore.h>
#include "BaseTask.h" // 前置定义
class MyThreadPool; class MyThread
{
public:
MyThread(MyThreadPool* mtp);
void Set_Task(BaseTask* task);
void Start_Task();
/* 线程启动函数 必须写成静态成员函数 传入的参数为类对象自己*/
static void* Start_Func(void* arg);
/* 完成一个任务后 询问线程池管理器是否有未完成的任务*/
bool Fetch_Task();
/* 无更多任务 让自己进入线程池栈*/
void Recycle();
private:
/* 用于挂起线程 */
sem_t sem;
pthread_t tid;
BaseTask* task;
MyThreadPool* mtp;
}; #endif

MyThread.cpp

 #include "MyThreadPool.h"
#include "MyThread.h" MyThread::MyThread(MyThreadPool* mtp)
{
sem_init(&sem,,);
this->mtp = mtp;
pthread_create(&tid,NULL,Start_Func,(void*)this);
} void MyThread::Set_Task(BaseTask* task)
{
this->task = task;
} void MyThread::Start_Task()
{
sem_post(&sem);
} void* MyThread::Start_Func(void* arg)
{
MyThread* mt = (MyThread*) arg;
while()
{
sem_wait(&mt->sem);
mt->task->run();
if(mt->Fetch_Task())
mt->Start_Task();
else
mt->Recycle();
}
} bool MyThread::Fetch_Task()
{
return mtp->FetchTask(this);
} void MyThread::Recycle()
{
mtp->Recycle(this);
}

MyThreadPool:线程池管理类,实现线程的创建管理和任务调度。

MyThreadPool.h

 #ifndef MYTHREADPOOL_H
#define MYTHREADPOOL_H #include <iostream>
#include <stack>
#include <queue>
#include "Mutex.h"
#include "BaseTask.h" class MyThread; class MyThreadPool
{
public:
/* no为要开辟的线程数目*/
MyThreadPool(int no);
/* 添加任务*/
void AddTask(BaseTask* task);
/* 供线程类调用 让线程类对象询问线程池任务队列中是否仍有任务未完成*/
bool FetchTask(MyThread* mt);
/* 回收线程 */
void Recycle(MyThread* mt);
private:
int no;
Mutex smutex;
Mutex qmutex; stack<MyThread*> sthread;
queue<BaseTask*> qtask;
}; #endif

MyThreadPool.cpp

 #include "MyThreadPool.h"
#include "MyThread.h" MyThreadPool::MyThreadPool(int no)
{
this->no = no; for(int i=;i<no;++i)
{
sthread.push(new MyThread(this));
}
} void MyThreadPool::AddTask(BaseTask* task)
{
smutex.Lock();
if (!sthread.empty())
{
MyThread* mt = sthread.top();
sthread.pop();
smutex.Unlock();
mt->Set_Task(task);
mt->Start_Task();
}
else
{
smutex.Unlock();
qmutex.Lock();
qtask.push(task);
qmutex.Unlock();
}
} bool MyThreadPool::FetchTask(MyThread* mt)
{
qmutex.Lock();
if (!qtask.empty())
{
mt->Set_Task(qtask.front());
qmutex.Unlock();
return true;
}
else
{
qmutex.Unlock();
return false;
}
} void MyThreadPool::Recycle(MyThread* mt)
{
smutex.Lock();
sthread.push(mt);
smutex.Unlock();
}

main.cpp

 #include "MyThread.h"
#include "MyThreadPool.h"
#include "Mutex.h"
#include "MyTask.h" int main()
{
MyThreadPool mtp();
while()
{
BaseTask* task = new MyTask;
mtp.AddTask(task);
sleep();
delete task;
task = NULL;
}
}

makefile

 pro: main.cpp libtp.a MyTask.cpp
g++ -lpthread main.cpp -L. -ltp MyTask.cpp -o pro libtp.a: MyThreadPool.o MyThread.o Mutex.o
ar cr libtp.a Mutex.o MyThreadPool.o MyThread.o MyThread.o:MyThread.cpp
g++ -c -lpthread MyThread.cpp -o MyThread.o MyThreadPool.o:MyThreadPool.cpp
g++ -c -lpthread MyThreadPool.cpp -o MyThreadPool.o Mutex.o:Mutex.cpp
g++ -c -lpthread Mutex.cpp -o Mutex.o clean:
rm libtp.a MyThreadPool.o Mutex.o MyThread.o pro

执行 make 成功后,执行./pro 即可

编译: 我首先将线程类(MyThread.o) 互斥类(Mutex.o) 和 线程池类(MyThreadPool.o) 打包成一个静态库

静态库留出两个接口 一个是线程池的初始化 另外一个是用户自己继承BaseTask的run函数后 调用线程池的类对象 AddTask接口去增加任务

所以使用者只需自己指定要开辟的线程数(线程池的构造函数) 和 自定义 任务类对象即可使用这个线程池.

ps:所有文件都放在同一个目录下

Linux C++线程池的更多相关文章

  1. linux C 线程池(物不可穷也~)

    Linux 多线程编程之 线程池 的原理和一个简单的C实现,提高对多线程编 程的认知,同步处理等操作,以及如何在实际项目中高效的利用多线程开 发. 1.  线程池介绍 为什么需要线程池??? 目前的大 ...

  2. Linux C++线程池实例

    想做一个多线程服务器测试程序,因此参考了github的一些实例,然后自己动手写了类似的代码来加深理解. 目前了解的线程池实现有2种思路: 第一种: 主进程创建一定数量的线程,并将其全部挂起,此时线程状 ...

  3. 基于linux与线程池实现文件管理

    项目要求 1.基本 用线程池实现一个大文件夹的拷贝,大文件夹嵌套很多小文件:实现复制到指定文件夹的全部文件夹. 2.扩充功能 显示进度条:拷贝耗时统计:类似linux的tree,不能直接用system ...

  4. Linux下线程池的理解与简单实现

    首先,线程池是什么?顾名思义,就是把一堆开辟好的线程放在一个池子里统一管理,就是一个线程池. 其次,为什么要用线程池,难道来一个请求给它申请一个线程,请求处理完了释放线程不行么?也行,但是如果创建线程 ...

  5. Linux简单线程池实现(带源码)

    这里给个线程池的实现代码,里面带有个应用小例子,方便学习使用,代码 GCC 编译可用.参照代码看下面介绍的线程池原理跟容易接受,百度云下载链接: http://pan.baidu.com/s/1i3z ...

  6. linux中线程池【转】

    本文转载自:http://blog.csdn.net/yusiguyuan/article/details/18401277 一.线程池 大多数的网络服务器,包括Web服务器都具有一个特点,就是单位时 ...

  7. Linux pthread 线程池实现

    基于pthread封装了一个简易的ThreadPool,具有以下特性: 1.具有优先级的任务队列 2.线程池大小可以二次调整,增加线程或者删除空闲线程 3.任务两种重写方式,重写run或者使用函数回调 ...

  8. 【Linux】线程池

    首先,线程池是什么?顾名思义,就是把一堆开辟好的线程放在一个池子里统一管理,就是一个线程池. 其次,为什么要用线程池,难道来一个请求给它申请一个线程,请求处理完了释放线程不行么?也行,但是如果创建线程 ...

  9. linux 条件变量与线程池

    条件变量Condition Variables 概述 1. 条件变量提供了另外一种线程同步的方式.如果没有条件变量,程序需要使用线程连续轮询(可能在临界区critical section内)方式检查条 ...

随机推荐

  1. jquery easyui-datagrid/treegrid 清空数据参考

    在使用easyui的treegrid或datagrid的过程经常会有这样的场景,如:需要按不同的类型加载数据时,如果选择的分类下没有数据应该把上次展示的数据清空,以免引用歧义.下面给出两种方法供初学者 ...

  2. jQuery .attr("checked")得undefined 问题解决

    出现此错误是因为JQuery版本升级的问题.所以此处应该使用.prop(); 那么,什么时候使用attr(),什么时候使用prop()?1.添加属性名称该属性就会生效应该使用prop();2.是有tr ...

  3. linux学习第一天

    linux touch 文件名mkdir -P 路径文件 cat 打开文件 vihostname 主机名ln 复制 ln -s 快捷方式cp 复制-r复制整个目录-p保持源文件属性不变-f强制复制mv ...

  4. mysql 增删改查最基本用法小结

    目录: 1.新建数据库 2.新建数据表 3.查看表结构 4.增删改查 建立一个数据库students 建立一块数据表class1 内容包括: id 主键 自动编号 无符号位 SMALLINT类型 na ...

  5. git 常用命令粗略总结

    本文版权归cxun所有,如有转载请注明出处与本文链接,谢谢!原文地址:http://www.cnblogs.com/cxun/p/5630190.html git的功能很强大,但是其实很简单,用来用去 ...

  6. 数据绑定控件之Repeater

    引言 前几篇的文章在说AJAX的内容,利用AJAX技术能够开发出高效运行的网站应用程序,不过在进行B/S项目开发时只拥有AJAX技术是远远不够的,踏入到B/S要学的东西会更多,但相较C/S的复杂逻辑结 ...

  7. Caffe + Ubuntu 14.04 64bit + 无CUDA(linux下安装caffe(无cuda)以及python接口)

    安装Caffe指导书 环境: Linux 64位 显卡为Intel + AMD,非英伟达显卡 无GPU 一. 安装准备工作 1. 以管理员身份登录 在左上角点击图标,搜索terminal(即终端),以 ...

  8. 3D数学的实际应用

    以前自己在学习三维程序开发时并没有在意3D数学在程序中的重要作用,但在实际工作中逐渐发现:自己忽视了3D数学的作用,我们实际开发工作总要求模型准确的变换,而不是强调渲染有多炫,那是游戏,如果是仿真程序 ...

  9. UEFI Bootable USB Flash Drive - Create in Windows(WIN7 WIN8)

    How to Create a Bootable UEFI USB Flash Drive for Installing Windows 7, Windows 8, or Windows 8.1 In ...

  10. JAVA join()方法

    转自:http://www.open-open.com/lib/view/open1371741636171.html 一.为什么要用join()方法 在很多情况下,主线程生成并起动了子线程,如果子线 ...