线程池是一种多线程处理形式,预先创建好一定数量的线程,将其保存于一个容器中(如vector), 处理过程中将任务添加到队列,然后从容器中取出线程后自动启动这些任务,具体实现如下。

以下是UML图,展示了类与类之间的大致关系,其中NonCopyable.h未给出。关于类之间的关系的表示,请参见

博客:http://www.cnblogs.com/liuling/archive/2013/05/03/classrelation.html


以下对各个类进行解释,给出代码并在注释中会说明每个函数的作用。

文件清单:

    下面的代码是头文件和实现分开,每一个头文件对应一个实现文件(.cpp)。Noncopyable.h 与test.cpp除外。所以代码经过调试,在Linux下可执行。

   
分享一个教训,我调了好久才发现这个低级错误,在编译时候记得是:g++ *.cpp -lpthread.h

1、Noncopyable类:

   
Nocopyable,顾名思义-不可复制。继承自Noncopyable的派生类,不可被复制,我们的策略是将其复制构造函数以及赋值构造函数放到私有区域中。见代码如下:

<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">/*************************************************************************
> File Name: Noncopyable.h
> Author: HOUJUN
> Mail:june506@163.com
> Created Time: Tue 25 Aug 2015 11:06:51 PM HKT
************************************************************************/ #ifndef _NONCOPYABLE_H
#define _NONCOPYABLE_H class Noncopyable
{
protected:
Noncopyable(){}
~Noncopyable(){}
private:
Noncopyable(const Noncopyable & rhs);
Noncopyable & operator=(const Noncopyable &rhs);
};
#endif</span></span></span>


2、Threadpool类:

一个线程池维护有一个任务缓冲器Buffer(内部有队列queue实现)和存储线程地址的vector<Thread*>。对外提供有getTask()与addTask()方法,分别用于向任务队列中取任务和向任务队列中添加任务。

<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">/*************************************************************************
> File Name: Threadpool.h
> Created Time: Tue 25 Aug 2015 11:39:48 PM HKT
************************************************************************/ /*************************************************************/
// 1、所谓“线程池”,就是预先把线程创建好,省去响应每次响应客户端时
//创建线程时间上的开销。线程的创建在start()函数中执行。stop()函数
//负责线程的回收。
//
// 2、线程池中有一个保存线程地址的数组,以及一个保存任务的队列。因此
//私有成员中用到两个整型来分别表示任务队列的大小,以及创建线程的数目
//
// 3、线程池提供一个addTask()方法,向任务缓存中添加任务,同时
//提供一个getTask()方法,从任务缓存中取任务。
//
// 4、threadFunc()函数是线程中将要执行的函数。
//
//
/*************************************************************/ #ifndef _THREADPOOL_H
#define _THREADPOOL_H #include "Buffer.h"
#include <vector>
class Task; //前向声明,将在实现文件中给出头文件
class Thread; class Threadpool
{
public:
Threadpool(int bufsize,int threadNum);
~Threadpool();
void start();
void stop();
void addTask(Task *task);
Task* getTask(); void threadFunc(); private:
int size_;
Buffer buffer_;
int threadNum_;
std::vector<Thread *> vecThreads_;
bool isExit_;
};
#endif</span></span></span>
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">/*************************************************************************
> File Name: Threadpool.cpp
> Created Time: Tue 25 Aug 2015 11:59:03 PM HKT
************************************************************************/ #include "Threadpool.h"
#include "Thread.h"
#include "MyPoolThread.h"
#include "Task.h" Threadpool::Threadpool(int bufsize,int threadNum)
:size_(bufsize),
buffer_(size_), //任务缓存的初始化
threadNum_(threadNum),
vecThreads_(threadNum_),
isExit_(false)
{} Threadpool::~Threadpool()
{
stop();
} void Threadpool::start()
{
for(int idx = 0;idx!=threadNum_;idx++)
{
Thread *pthread = new MyPoolThread(*this);
vecThreads_.push_back(pthread);
pthread->start();
} } void Threadpool::stop()
{
if(isExit_)
{
isExit_=true;
std::vector<Thread*>::iterator iter;
for(iter = vecThreads_.begin();iter!=vecThreads_.end();iter++)
{
(*iter)->join();
delete *iter; //释放iter所指向的空间
}
vecThreads_.clear();
}
} void Threadpool::addTask(Task* task)
{
buffer_.push(task);
} Task* Threadpool::getTask()
{
return buffer_.pop();
} void Threadpool::threadFunc()
{
while(!isExit_)
{
Task *task = getTask();
if(task != NULL)
task->process();
}
}
</span></span></span>

3、Buffer类:

Buffer是一个任务缓冲区,即用来存取任务。由于Buffer是共享资源,因此要用互斥锁与条件变量来进行同步。

<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">/*************************************************************************
> File Name: Buffer.h
> Created Time: Tue 25 Aug 2015 10:09:19 PM HKT
************************************************************************/ #ifndef __BUFFER_H
#define __BUFFER_H #include "MutexLock.h"
#include "Condition.h"
#include <queue> class Task; //前向声明
class Buffer
{
public:
Buffer(int size);
void push(Task* task);
Task* pop();
bool empty();
bool full(); private:
MutexLock mutex_;
Condition notfull_;
Condition notempty_;
int size_;
std::queue<Task*> que_;
};
#endif</span></span></span>
<span style="font-size:18px;"><span style="font-size:18px;"><pre name="code" class="cpp"><span style="font-size:18px;">/*************************************************************************
> File Name: Buffer.cpp
> Created Time: Tue 25 Aug 2015 10:14:41 PM HKT
************************************************************************/ #include "Buffer.h"
#include "Task.h" /************************************************/
//构造函数
//由于Buffer 与MutexLock,Condition是组合关系,因此
//Buffer负责他们的初始化工作
//mutex_()为对象初始化
/************************************************/
Buffer::Buffer(int size)
:mutex_(),
notfull_(mutex_),
notempty_(mutex_),
size_(size)
{} //任务缓存的判空
bool Buffer::empty()
{
return (que_.size()==0);
} //任务缓存的判满
bool Buffer::full()
{
return (que_.size()==size_);
} /********************************************************/
//1、先加锁
//2、如果满,睡眠等待不满
//3、当满足不满(即有空位)的条件,唤醒阻塞等待添加任务的线程
//4、向队列添加任务
//5、通知等到非空(即有任务)的条件,唤醒等待取任务的线程
/*********************************************************/
void Buffer::push(Task* task)
{
MutexLockGuard guard(mutex_);
while(full())
notfull_.wait();
que_.push(task);
notempty_.notify();
} /********************************************************/
//1、先加锁
//2、如果空,睡眠等待非空
//3、通知等到非空(即有任务可执行)的条件,唤醒等待取任务的线程
//4、从队列取任务,返回任务的地址
//5、当满足不满(即有空位)的条件,唤醒阻塞等待添加任务的线程
/*********************************************************/
Task* Buffer::pop()
{
MutexLockGuard guard(mutex_);
while(empty())
notempty_.wait();
Task* task = que_.front();
que_.pop();
notfull_.notify();
return task;
}</span></span></span>

4、MutexLock类:

当对临界区数据进行操作的时候,要进行同步,否则后果不可预见。要用到互斥锁mutex。

<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-family:SimSun;font-size:18px;">/*************************************************************************
> File Name: MutexLock.h
> Created Time: Tue 25 Aug 2015 10:49:24 PM HKT
************************************************************************/ #ifndef __MUTEXLOCK_H
#define __MUTEXLOCK_H #include "Noncopyable.h" //条件变量为系统资源类,禁止复制
#include <pthread.h> //互斥量定义在线程头文件中 /******************************************/
//互斥锁无非就是进行加锁与解锁,因此除了提供
//一个构造函数与一个析构函数外,还有一个加锁
//和一个解锁函数。同时,还有一个用于获取当前
//互斥量的一个指针。
/******************************************/
class MutexLock : private Noncopyable
{
public:
MutexLock();
~MutexLock();
void lock();
void unlock();
pthread_mutex_t * getMutexPtr();
private:
pthread_mutex_t mutex_;
}; /********************************************/
//基于MutexLock类的一个操作类,私有成员是mutex_
//在创建MutexGuard对象的时候进行加锁,因此我们
//可以不去直接操作MutexLock的lock()函数。
//在析构对象的时候解锁_
/********************************************/
class MutexLockGuard
{
public:
MutexLockGuard(MutexLock &mutex)
:mutex_(mutex)
{
mutex_.lock();
} ~MutexLockGuard()
{
mutex_.unlock();
}
private:
MutexLock & mutex_;
};
#endif</span></span></span></span>
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">/*************************************************************************
> File Name: MutexLock.cpp
> Created Time: Tue 25 Aug 2015 11:11:36 PM HKT
************************************************************************/ #include "MutexLock.h"
MutexLock::MutexLock()
{
pthread_mutex_init(&mutex_,NULL);
} void MutexLock::lock()
{
pthread_mutex_lock(&mutex_);
} void MutexLock::unlock()
{
pthread_mutex_unlock(&mutex_);
} pthread_mutex_t * MutexLock::getMutexPtr()
{
return &mutex_;
} MutexLock::~MutexLock()
{
pthread_mutex_destroy(&mutex_);
}</span></span></span>

5、Condition类:

通常情况下,条件变量与互斥量总会在同步中同时出现,两者相互配合,完成同步工作。

<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-family:SimSun;font-size:18px;">/*************************************************************************
> File Name: Condition.h
> Created Time: Tue 25 Aug 2015 11:18:30 PM HKT
************************************************************************/ #ifndef _CONDITION_H
#define _CONDITION_H #include "Noncopyable.h"
#include <pthread.h> class MutexLock; //前向声明
class Condition : private Noncopyable
{
public:
Condition(MutexLock & mutex);
void wait();
void notify();
void notifyall();
~Condition();
private:
pthread_cond_t cond_;
MutexLock & mutex_;
};
#endif</span></span> </span></span>
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-family:SimSun;font-size:18px;">/*************************************************************************
> File Name: Condition.cpp
> Created Time: Tue 25 Aug 2015 11:24:58 PM HKT
************************************************************************/ #include "MutexLock.h"
#include "Condition.h" /***************************************/
//由于Condition中的wait()函数要使用到
//MutexLock对象,因此在此要传入一个MutexLock
//对象,对成员函数进行初始化
//
//以下函数体中的的系统调用,要求我们熟悉
//pthread_cond_t的API使用方法
//
/***************************************/
Condition::Condition(MutexLock & mutex) //Condition依赖MutexLock
:mutex_(mutex)
{
pthread_cond_init(&cond_,NULL);
} Condition::~Condition()
{
pthread_cond_destroy(&cond_);
} void Condition::wait()
{
pthread_cond_wait(&cond_,mutex_.getMutexPtr());
} void Condition::notify()
{
pthread_cond_signal(&cond_);
} void Condition::notifyall()
{
pthread_cond_broadcast(&cond_);
}</span></span></span></span>

6、Thread类

Thread类是一个虚类,其中有一个虚函数run()。

<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">/*************************************************************************
> File Name: Thread.h
> Created Time: Wed 26 Aug 2015 11:22:08 AM HKT
************************************************************************/ #ifndef _THREAD_H
#define _THREAD_H
#include "Noncopyable.h"
#include <pthread.h>
class Thread : private Noncopyable
{
public:
Thread()
:pthId_(0),
isRunning_(false)
{}
void start();
void join();
virtual void run()=0;
~Thread();
static void *runInThread(void *arg);
private:
pthread_t pthId_;
bool isRunning_;
};
#endif</span></span></span>
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;"><span style="font-family:SimSun;font-size:18px;">/*************************************************************************
> File Name: Thread.cpp
> Created Time: Wed 26 Aug 2015 11:26:43 AM HKT
************************************************************************/ #include "Thread.h" /************************************/
//调用start()创建线程,调用phtread_create()
//设置运行标志位true
/************************************/
void Thread::start()
{
pthread_create(&pthId_,NULL,runInThread,this);
isRunning_=true;
} /************************************/
//调用join()回收线程
//设置运行标志位为false
//
//注意:创建者调用join()函数回收子线程,
//当子线程没有运行结束,则创建者会阻塞
//等待子线程结束。
/************************************/
void Thread::join()
{
pthread_join(pthId_,NULL);
isRunning_=false;
} /*************************************/
//析构函数
//
//但是我们并不希望主线程吊死在一棵树上,
//它还有其它任务,所以:
// pthread_detach(pthId),将线程状态设置
//为detached状态,当线程运行结束时候自动
//释放资源。(非阻塞,可立即返回)
/*************************************/
Thread::~Thread()
{
if(isRunning_)
{
pthread_detach(pthId_);
isRunning_=false;
}
} /********************************************/
//arg是在创建线程时候传入的this,再此将void类型
//的arg强转成Thread类型。
/********************************************/
void *Thread::runInThread(void *arg)
{
Thread *pThread = static_cast<Thread*>(arg);
pThread->run();
return NULL;
}
</span></span></span></span>

7、MyPoolThread类

MyPoolThread类是Thread类的实现类。

<span style="font-size:18px;">/*************************************************************************
> File Name: MyPoolThread.h
> Created Time: Wed 26 Aug 2015 03:45:46 PM HKT
************************************************************************/ #ifndef _MYPOOLTHREAD_H
#define _MYPOOLTHREAD_H /***************************************/
//1、MyPoolThread继承自Thread,拥有Thread
//的所有非私有成员及函数。
//
//2、之所以要传入线程池的引用,是因为
//Thread中的run()方法要执行线程池中的
//threadFunc()方法
/***************************************/
#include "Thread.h"
class Threadpool;
class MyPoolThread : public Thread
{
public:
MyPoolThread(Threadpool &threadpool);
void run();
private:
Threadpool &threadpool_;
};
#endif</span>
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">/*************************************************************************
> File Name: MyPoolThread.cpp
> Created Time: Wed 26 Aug 2015 03:51:05 PM HKT
************************************************************************/ #include "MyPoolThread.h"
#include "Threadpool.h" //在.h文件中进行前向声明
MyPoolThread::MyPoolThread(Threadpool & threadpool)
:threadpool_(threadpool)
{} void MyPoolThread::run()
{
threadpool_.threadFunc();
}</span></span></span>

8、Task类

任务是用户让线程池做的事情,它将作为一个参数传给线程池,让线程池将它添加到任务队列中,等待工作线程将其完成。以下的任务封装了一个方法,该方法是产生随机数

<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">/*************************************************************************
> File Name: Task.h
> Created Time: Wed 26 Aug 2015 03:32:53 PM HKT
************************************************************************/ #ifndef _TASK_H
#define _TASK_H /***********************************/
//Task就是一个执行的任务
/***********************************/
//Task接口类
class Task
{
public:
virtual void process()=0;
}; //Task的实现类
class MyTask :public Task
{
public:
void process();
};
#endif
</span></span></span>
<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">/*************************************************************************
> File Name: Task.cpp
> Created Time: Wed 26 Aug 2015 03:35:45 PM HKT
************************************************************************/ #include "Task.h"
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <iostream> void MyTask::process()
{
srand(time(NULL));
int num = rand()%100;
std::cout<<"product a number:"<<num<<std::endl;
sleep(2);
}</span></span></span>

9、Test类:

至此,Threadpool类的封装已经完成,接下来让我们来使用它。

<span style="font-size:18px;"><span style="font-size:18px;"><span style="font-size:18px;">/*************************************************************************
> File Name: test.cpp
> Author: HOUJUN
> Mail:june506@163.com
> Created Time: Wed 26 Aug 2015 03:55:24 PM HKT
************************************************************************/ #include "Threadpool.h"
#include "Task.h"
#include <unistd.h> int main()
{
Threadpool threadpool(5,4);
threadpool.start();
Task *ptask = new MyTask;
while(1)
{
threadpool.addTask(ptask);
sleep(1);
}
threadpool.stop(); return 0;
}</span></span></span>


运行结果:

以上就是我对Threadpool封装的总结,分享的同时有希望各位大神指点,找出错误,共同进步。

版权声明:本文为博主原创文章,未经博主允许不得转载。

面向对象的线程池Threadpool的封装的更多相关文章

  1. 多线程Thread,线程池ThreadPool

    首先我们先增加一个公用方法DoSomethingLong(string name),这个方法下面的举例中都有可能用到 #region Private Method /// <summary> ...

  2. 线程池ThreadPool的常用方法介绍

    线程池ThreadPool的常用方法介绍 如果您理解了线程池目的及优点后,让我们温故下线程池的常用的几个方法: 1. public static Boolean QueueUserWorkItem(W ...

  3. Python之路(第四十六篇)多种方法实现python线程池(threadpool模块\multiprocessing.dummy模块\concurrent.futures模块)

    一.线程池 很久(python2.6)之前python没有官方的线程池模块,只有第三方的threadpool模块, 之后再python2.6加入了multiprocessing.dummy 作为可以使 ...

  4. 线程池ThreadPool的初探

    一.线程池的适用范围 在日常使用多线程开发的时候,一般都构造一个Thread示例,然后调用Start使之执行.如果一个线程它大部分时间花费在等待某个事件响应的发生然后才予以响应:或者如果在一定期间内重 ...

  5. C#多线程学习 之 线程池[ThreadPool](转)

    在多线程的程序中,经常会出现两种情况: 一种情况:   应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应                   这一般使用ThreadPo ...

  6. 高效线程池(threadpool)的实现

    高效线程池(threadpool)的实现 Nodejs编程是全异步的,这就意味着我们不必每次都阻塞等待该次操作的结果,而事件完成(就绪)时会主动回调通知我们.在网络编程中,一般都是基于Reactor线 ...

  7. 多线程系列 线程池ThreadPool

    上一篇文章我们总结了多线程最基础的知识点Thread,我们知道了如何开启一个新的异步线程去做一些事情.可是当我们要开启很多线程的时候,如果仍然使用Thread我们需要去管理每一个线程的启动,挂起和终止 ...

  8. C# -- 使用线程池 ThreadPool 执行多线程任务

    C# -- 使用线程池 ThreadPool 执行多线程任务 1. 使用线程池 class Program { static void Main(string[] args) { WaitCallba ...

  9. C# 线程池ThreadPool的用法简析

    https://blog.csdn.net/smooth_tailor/article/details/52460566 什么是线程池?为什么要用线程池?怎么用线程池? 1. 什么是线程池? .NET ...

随机推荐

  1. 搭建yum仓库与定制rpm包

    笔者Q:972581034 交流群:605799367.有任何疑问可与笔者或加群交流 当我们自动化部署集群的时候,想要快速的安装所有服务,搭建yum仓库与定制rpm包是我们首先要做的 原创作品,转载请 ...

  2. plus、max、Pro、Edge

    plus.max.Pro.Edge等后缀到底什么意思? Plus:比好更好.比牛X更牛X 译成中文是:加.和.正的-的意思.比如oneplus中文名就是一加.用于手机命名表示配置更加牛X,最早是由iP ...

  3. 使用autoc js生成文章目录(侧边)导航栏

    介绍: autocjs 是一个专门用来生成文章目录(Table of Contents)导航的工具.autocjs 会查找文章指定区域中的所有 h1~h6 的标签,并自动分析文章的层次结构,生成文章的 ...

  4. Django中url的生成过程详解

    在前面我们知道,Django启动之前会执行admin.py中的autodiscover()方法. def autodiscover(): autodiscover_modules('admin', r ...

  5. CentOS上安装MongoDB速记

    测试环境版本CentOS 6.5 先创建安装目标文件夹并进入至该文件夹: mkdir /opt/mongodb cd /opt/mongodb 给mongodb创建用户及用户组: groupadd m ...

  6. windows系统下安装Eclipse for PHP

    第一步: 如果机器上没有java运行环境,请先安装   第二步: 下载eclipse,下载地址: http://www.eclipse.org/downloads/ 选择对应版本,本人选择的是64位版 ...

  7. Linux普通用户使用sudo权限启停apache服务

    sudo的工作过程如下: 1,用户执行sudo时,系统会主动寻找/etc/sudoers文件,判断该用户是否有执行sudo的权限 2,确认用户具有可执行sudo的权限后,让用户输入密码确认 3,若密码 ...

  8. BZOJ 4698: Sdoi2008 Sandy的卡片 [后缀自动机]

    4698: Sdoi2008 Sandy的卡片 题意:差分后就是多个串LCS SAM+map大法好 模板打错 智力-2 #include <iostream> #include <c ...

  9. BZOJ 1483: [HNOI2009]梦幻布丁 [链表启发式合并]

    1483: [HNOI2009]梦幻布丁 题意:一个带颜色序列,一种颜色合并到另一种,询问有多少颜色段 一种颜色开一个链表,每次遍历小的合并到大的里,顺带维护答案 等等,合并方向有规定? 令col[x ...

  10. POJ 2187 Beauty Contest [凸包 旋转卡壳]

    Beauty Contest Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 36113   Accepted: 11204 ...