这篇文章简单讨论下线程池。
一.什么是线程池
线程池简单来时就是维护了一组线程的池子,这组线程执行一些相似任务。是一种线程的使用方式。
二.为什么要用线程池
有的时候系统需要处理大量相似任务,频繁创建销毁线程会影响系统性能,这个时候就可以维护一组线程专门处理这些任务。
三.如何实现线程池
重点来了,这里展示一种简易的线程池实现方式,主要是为了描述一下线程池的一种运行模式。
直接看代码。
//threadpool.h
#ifndef THREADPOOL_H
#define THREADPOOL_H
#include <vector>
#include <utility>
#include <mutex>
#include <functional>
#include <queue>
#include <condition_variable>
#include <thread>
#define ERR_MES_1 "输入值不合法"
enum Level
{
Level_0,
Level_1,
Level_2
};
using Task = std::function<void()>;
using TaskPair = std::pair<Level, Task>;
class TaskPriorityCompare
{
public:
bool operator()(TaskPair taskPair1, TaskPair taskPair2)
{
return taskPair1.first > taskPair2.first;
}
};
using ThreadVec = std::vector<std::thread*>;
using TaskQue = std::priority_queue<TaskPair, std::vector<TaskPair>, TaskPriorityCompare>;
using FinishTaskQue = std::queue<Task>;
using UniqueLock = std::unique_lock<std::mutex>;
class ThreadPool
{
public:
ThreadPool() = default;
~ThreadPool()noexcept = default;
bool Start(int ThreadPoolSize = 3);
void Stop();
void AddTask(const Task& task, Level level = Level_2);
protected:
void LoopExecuteThread();
Task TakeTask();
private:
bool m_isStart;
std::mutex m_mutex;
std::condition_variable m_condVari;
int m_threadPoolSize;
ThreadVec m_threadVec;
TaskQue m_taskQue;
FinishTaskQue m_finishTaskQue;
int m_lastErrCode;
std::string m_lastErrMes;
};
#endif // !THREADPOOL_H
//threadpool.cpp
#include "threadpool.h"
#include <iostream>
bool ThreadPool::Start(int threadPoolSize)
{
if (threadPoolSize < 1)
{
m_lastErrCode = 1;
m_lastErrMes = ERR_MES_1;
return false;
}
m_isStart = true;
m_threadPoolSize = threadPoolSize;
for (int i = 0; i < m_threadPoolSize; i++)
{
m_threadVec.push_back(new std::thread(&ThreadPool::LoopExecuteThread, this));
}
return true;
}
void ThreadPool::Stop()
{
m_isStart = false;
m_condVari.notify_all();
for (auto ite = m_threadVec.begin(); ite != m_threadVec.end(); ite++)
{
(*ite)->join();
delete* ite;
}
m_threadVec.clear();
}
void ThreadPool::AddTask(const Task& task, Level level)
{
UniqueLock lock(m_mutex);
TaskPair taskPair(level, task);
m_taskQue.push(taskPair);
m_condVari.notify_one();
}
void ThreadPool::LoopExecuteThread()
{
UniqueLock lock(m_mutex);
lock.unlock();
while (m_isStart)
{
lock.lock();
if (m_taskQue.empty())
{
m_condVari.wait(lock);
}
std::cout << std::this_thread::get_id() << std::endl;
Task task = TakeTask();
lock.unlock();
if (task)
{
task();
m_finishTaskQue.push(task);
}
}
}
Task ThreadPool::TakeTask()
{
if (!m_taskQue.empty())
{
Task task;
task = m_taskQue.top().second;
m_taskQue.pop();
return task;
}
return nullptr;
}
//main.cpp
#include "threadpool.h"
#include <iostream>
void Fun1()
{
std::cout << "Fun1 exec" << std::endl;
}
void Fun2()
{
std::cout << "Fun2 exec" << std::endl;
}
void Fun3()
{
std::cout << "Fun3 exec" << std::endl;
}
int main(void)
{
ThreadPool threadPool;
int i = 3;
threadPool.Start(i);
for (int i = 0; i < 10; i++)
{
threadPool.AddTask(Fun1, Level_2);
threadPool.AddTask(Fun2, Level_1);
threadPool.AddTask(Fun3, Level_0);
}
std::this_thread::sleep_for(std::chrono::seconds(3));
threadPool.Stop();
return 0;
}