2021-09-06 c++11实现最简单的线程池模型

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"; 
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

feng_blog6688

只需一个赞,谢谢你的鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值