c++11实现最简单的线程池模型
线程池主要解决频繁执行一类任务,避免多次创建线程造成系统资源消耗。线程池可以实现任务执行体复用,减少了线程的创建频率。主要用到如下知识点:
知识点
std::thread
c++11支持的线程库对象,支持高并发,拷贝构造函数(被禁用),意味着 std::thread
对象不可拷贝构造。如何创建一个thread对象,采用以下方法:
void f1()
{
std::cout<<"f1"<<std::endl;
}
void f2(int n)
{
std::cout<<"f2"<<n<<std::endl;
}
std::thread t1(f1);
std::thread t1(f2,2);
//类的成员函数中创建线程
class A
{
A(){}
~A(){}
void run()
{
std::cout<<"hello"<<std::endl;
}
void init()
{
std::thread(&A::run, this);
}
}
std::this_thread
包含访问当前线程的一系列函数。如下
get_id 获取线程id
yield 当前线程放弃执行,给实现重新调度的机会,允许其他线程运行,该线程回到准备状态,重新分配资源。调用该方法后,可能执行其他线程,也可能还是执行该线程。
std::condition_variable
当 std::condition_variable 对象的某个 wait 函数被调用的时候,它使用 std::unique_lock(通过 std::mutex) 来锁住当前线程。当前线程会一直被阻塞,直到另外一个线程在相同的 std::condition_variable 对象上调用了 notification 函数来唤醒当前线程。在第二种情况下(即设置了 Predicate),只有当 pred 条件为 false 时调用 wait() 才会阻塞当前线程,并且在收到其他线程的通知后只有当 pred 为 true 时才会被解除阻塞。
std::mutex
普通的互斥锁,保证多线程情况下线程同步。
std::unique_lock
为锁管理模板类,是对通用mutex的封装。
线程池实现
线程池主要思想:一个线程队列,一个任务队列,线程队列是消费者,任务队列是生产者,线程池创建后形成一个任务队列和一个线程队列,每个线程的执行函数在等待任务执行,没有任务就阻塞该线程,向任务队列中添加任务,并唤醒一个等待线程,这样等待线程就可以去执行任务。
任务基类的头文件定义:
#pragma once
#include <string>
using namespace std;
class CTask
{
public:
CTask();
~CTask();
void SetTaskName(char* taskname);
//指定Run接口
virtual void Run(/*void *pvargs*/) = 0;
int GetTaskNo(void);
void SetTaskNo(int taskno);
char* GetTaskName(void) const;
private:
int m_taskNo; //任务编号
string m_taskName; //任务名称
};
任务基类的源文件定义:
#include "pch.h"
#include "CTask.h"
CTask::CTask():/*m_pWorkThread(NULL),*/
m_taskNo(0),
m_taskName("")
{
}
CTask::~CTask()
{
}
void CTask::SetTaskName(char* taskname)
{
m_taskName = taskname;
}
//设置或获取任务编号
int CTask::GetTaskNo(void)
{
return m_taskNo;
}
void CTask::SetTaskNo(int jobno)
{
m_taskNo = jobno;
}
//设置或获取任务名称
char* CTask::GetTaskName(void) const
{
return (char *)m_taskName.c_str();
}
线程池类的头文件定义:
#pragma once
#include <vector>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <sstream>
#include <iostream>
#include "CTask.h"
using namespace std;
class ThreadPool
{
public:
ThreadPool();
ThreadPool(size_t nThreads);
~ThreadPool();
public:
//初始化线程池
void InitThreadPool(size_t nThreads);
//线程运行函数
void Run();
void Stop();
void AddTask(std::shared_ptr<CTask > spTask);
int GetCurrentThreadId();
private:
//线程池
std::vector<std::thread > m_workerThreads;
//任务队列
std::queue<std::shared_ptr<CTask > > m_spTaskQueue;
//线程取任务同步互斥量
std::mutex m_TaskQueue_Mutex;
//线程执行任务的条件允许变量
std::condition_variable m_task_cv;
//停止信号量
bool m_bStop;
};
线程池类的源文件定义:
#include "pch.h"
#include "ThreadPool.h"
ThreadPool::ThreadPool()
:m_bStop(false)
{
}
ThreadPool::ThreadPool(size_t nThreads)
: m_bStop(false)
{
string strLog;
for (size_t i = 0; i < nThreads; i++)
{
m_workerThreads.push_back(std::thread(&ThreadPool::Run, this));
}
for (std::thread &worker : m_workerThreads)
{
std::thread::id threadid = worker.get_id();
std::ostringstream oss;
oss << threadid;
std::string stid = oss.str();
int m_ThreadID = std::stoull(stid);
strLog.clear();
strLog = strLog + "线程池创建子线程 [ " + std::to_string(m_ThreadID) + " ]";
std::cout << strLog << std::endl;
}
}
ThreadPool::~ThreadPool()
{
if (!m_bStop)
{
std::cout << "调用析构函数" << std::endl;
{
std::unique_lock<std::mutex> lock(m_TaskQueue_Mutex);
m_bStop = true;
}
m_task_cv.notify_all();
for (std::thread &worker : m_workerThreads)
{
if(worker.joinable())
worker.join();
}
std::cout << "调用析构函数结束" << std::endl;
}
}
void ThreadPool::InitThreadPool(size_t nThreads)
{
string strLog;
for (size_t i = 0; i < nThreads; i++)
{
m_workerThreads.push_back(std::thread(&ThreadPool::Run, this));
}
for (std::thread &worker : m_workerThreads)
{
std::thread::id threadid = worker.get_id();
std::ostringstream oss;
oss << threadid;
std::string stid = oss.str();
int m_ThreadID = std::stoull(stid);
strLog.clear();
strLog = strLog + "线程池创建子线程 [ " + std::to_string(m_ThreadID) + " ]";
std::cout << strLog << std::endl;
}
}
void ThreadPool::Run()
{
for (;;)//线程在执行
{
//等待取任务阻塞线程,知道接收到停止信号量,或者任务队列不为空时停止阻塞线程
std::unique_lock<std::mutex> lock(this->m_TaskQueue_Mutex);
this->m_task_cv.wait(lock,
[this] { return this->m_bStop || !this->m_spTaskQueue.empty(); }); //|| !this->m_spTaskQueue.empty()
if (this->m_bStop)
break;
//取任务
shared_ptr<CTask > wpTask = m_spTaskQueue.front();
//任务队列移除该任务
m_spTaskQueue.pop();
//执行任务
std::thread::id tId = std::this_thread::get_id();
std::ostringstream oss;
oss << tId;
std::string stid = oss.str();
int nThreadId = std::stoull(stid);
std::cout << "线程 [" << GetCurrentThreadId() << "]执行任务" << std::endl;
wpTask->Run();
}
std::cout << "线程 [" << GetCurrentThreadId() << "]执行任务结束" << std::endl;
}
void ThreadPool::Stop()
{
{
std::unique_lock<std::mutex> lock(m_TaskQueue_Mutex);
}
m_task_cv.notify_all();
m_bStop = true;
for (std::thread &worker : m_workerThreads)
worker.join();
}
void ThreadPool::AddTask(std::shared_ptr<CTask > spTask)
{
if (!m_bStop)//线程未结束
{
std::unique_lock<std::mutex> lk(m_TaskQueue_Mutex);
m_spTaskQueue.emplace(spTask);
m_task_cv.notify_one();
}
}
int ThreadPool::GetCurrentThreadId()
{
std::thread::id tId= std::this_thread::get_id();
std::ostringstream oss;
oss << tId;
std::string stid = oss.str();
int nThreadId = std::stoull(stid);
return nThreadId;
}
main函数测试
#include "pch.h"
#include <iostream>
#include<windows.h>
#include "CTask.h"
#include "ThreadPool.h"
class CWorkTask : public CTask
{
public:
CWorkTask()
{
i = 0;
}
~CWorkTask()
{
}
void Run()
{
std::string strLog = "";
strLog += "Task No.[ " + std::to_string(GetTaskNo()) + " ]" + "Task name [ " + GetTaskName() + " ]";
std::cout << strLog << endl;
}
public:
int i;
};
class CWorkTask2 : public CTask
{
public:
CWorkTask2()
{
i = 0;
}
~CWorkTask2()
{
}
void Run()
{
std::string strLog = "";
strLog += "Task No.[ " + std::to_string(GetTaskNo()) + " ]" + "Task name [ " + GetTaskName() + " ]";
std::cout << strLog << endl;
}
public:
int i;
};
int main()
{
ThreadPool pool(10);
for (int i = 0; i < 10000; i++)
{
char cTaskName[50] = { 0x00 };
CWorkTask * pTask = new CWorkTask();
pTask->i = i + 1;
pTask->SetTaskNo(i + 1);
std::snprintf(cTaskName, sizeof(cTaskName), "task%03d", i + 1);
pTask->SetTaskName(cTaskName);
shared_ptr<CWorkTask > spTask;
spTask.reset(pTask);
pool.AddTask(spTask);
//std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
char cTaskName[50] = { 0x00 };
CWorkTask * pTask = new CWorkTask();
pTask->i = 999;
pTask->SetTaskNo(999);
std::snprintf(cTaskName, sizeof(cTaskName), "工作任务%03d", 999);
pTask->SetTaskName(cTaskName);
shared_ptr<CWorkTask > spTask;
spTask.reset(pTask);
pool.AddTask(spTask);
//pool.Stop();
while (1)
{
Sleep(10);
}
std::cout << "Hello World!\n";
}