C++11 实现简单的线程池
需要提前了解一些C++11的线程知识
需要提前了解,thread 的创建,mutex的基本使用,unique_lock与mutex绑定,函数对象化包装(function),移动语义。
线程池设计思想
线程池首先需要进行初始化,本代码初始化了5个线程(手动指定),开始5个线程会被阻塞,等待任务队列中有任务,任务存储在queue队列中,当队列中有任务的时候,会唤醒一个线程来处理此任务。任务队列大小本程序指定了3个。
MyThreadPool.h
#pragma once
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <vector>
#include <queue>
#define TASKNUM 3
using namespace std;
class ThreadPool
{
public:
typedef function<void()> Task; //把调用的函数包装成一个对象。当作一个任务对象
ThreadPool();
void initThread(int num); //初始化线程池启动线程
void addTask(const Task& t);
void setsize(int num); //设置线程数量
void runTask(); //执行任务
void Alljoin(); //主线程等待子线程结束
~ThreadPool();
private:
//线程个数
int m_threadnum;
//线程数组
vector<thread> m_threads;
//任务队列
queue<Task> m_task;
//互斥锁
mutex m_mtx;
//条件变量
condition_variable m_cond; //用于线程的唤醒与等待
//判断队列对空对满
bool m_isEmpty;
bool m_isFull;
//线程池工作结束为真
bool m_done;
};
MyThreadPool.cpp
#include "ThreadPool.h"
//初始化变量
ThreadPool::ThreadPool():m_isFull(false),m_isEmpty(true),m_done(false)
{
}
/** @fn void ThreadPool::start(int num)
* @brief 初始化线程池
* @param(OUT) int num
* @param(IN) int num
* @returns void
*/
void ThreadPool::initThread(int num)
{
setsize(num);
for (int i = 0;i < num; i++)
{
m_threads.push_back(thread(&ThreadPool::runTask,this));
}
}
/** @fn void ThreadPool::addTask(const Task&t)
* @brief 添加任务
* @param(OUT) const Task & t
* @param(IN) const Task & t
* @returns void
*/
void ThreadPool::addTask(const Task &t)
{
if (!m_done) //线程池在工作
{
unique_lock<mutex> lk(m_mtx);
while(m_isFull) //如果任务队列满了就循环等待
{
m_cond.wait(lk);
}
//当队列不满的时候加入到队列中
m_task.push(t);
if (TASKNUM == m_task.size())
{
m_isFull = true;
}
cout <<"Add a task success"<<endl;
m_isEmpty = false;
m_cond.notify_one(); //通知一个线程来调用。
}
}
void ThreadPool::setsize(int num)
{
this->m_threadnum = num;
}
/** @fn void ThreadPool::runTask()
* @brief 执行线程入口函数
* @returns void
*/
void ThreadPool::runTask()
{
while (!m_done)
{
unique_lock<mutex> lk(m_mtx);
while (m_isEmpty)
{
m_cond.wait(lk);
}
//移动语义
Task ta;
ta = move(m_task.front()); //将队列中第一个任务移给ta,进行执行。使用move为了减少内存的频繁创建与释放。
m_task.pop();
if (0 == m_task.size())
{
m_isEmpty = true;
}
m_isFull = false;
m_cond.notify_one();
lk.unlock(); //在这里解锁在这里其实已经实现了从队列中一个一个的调用任务
ta(); //任务已经分配了一个线程在执行,不会发生错乱。
}
}
/** @fn void ThreadPool::finish()
* @brief 等待子线程退出
* @returns void
*/
void ThreadPool::Alljoin()
{
for (int i = 0;i < m_threadnum;i++)
{
m_threads[i].join();
}
}
ThreadPool::~ThreadPool()
{
}
main.cpp
#include<iostream>
#include "ThreadPool.h"
using namespace std;
void func(int i)
{
cout <<"task finish "<<i<<" 线程id = "<<this_thread::get_id()<<endl;
}
int main(int argc,char *argv[])
{
ThreadPool p;
p.initThread(5); //初始化线程池
static int num = 0;
while (1) {
num++;
//this_thread::sleep_for(chrono::seconds(1)); //延时1s
auto task = bind(func,num); //把函数与参数绑定到一起
p.addTask(task);
}
p.Alljoin();
return 0;
}