C++线程池
使用线程情况比较频繁的地方,由于线程的创建及销毁都会产生对资源的占用及性能的损耗。为了优化性能,提升效率,在这种场景中,就应该使用线程池来处理任务。
线程池创建的关键点:
- 装载线程的容器,在C++中使用vector
- 装载任务的容器,一般使用队列,满足先进先出的特性
- 读写任务队列时,需要使用互斥锁,防止多线程读写异常
- 线程保活的无限循环中,需要添加一个有任务时运行,无任务时停止的控制器,防止CPU空转。在C++中使用条件变量
- 线程启停标识
依据以上关键点,开始编写相应的代码。首次创建线程池类,一般情况下,该类是单例类。
ThreadPool.h
#ifndef THREAD_POOL_H
#define THREAD_POOL_H
#include <thread>
#include <vector>
#include <queue>
#include <mutex>
#include <condition_variable>
#include <functional>
class ThreadPool {
public:
static ThreadPool* GetInstance(int number);
private:
ThreadPool(int number);
~ThreadPool();
public:
template<typename F, typename... Args>
void AddTask(F&& func, Args&&... args)
{
std::unique_lock<std::mutex> lock(m_Mutex);
std::function<void()> task = std::bind(std::forward<F> func, std::forward<Args>(args)...);
m_TaskQueue.emplace(std::move(task));
lock.unlock();
m_CV.notify_one();
}
private:
// first: thread container
// second: task queue
// third: task queue mutex lock
// forth: thread keep alive condition varible
// fifth: thread start/stop flag
// sixth: storage thread count
std::vector<std::thread> m_Threads;
std::queue<std::function<void()>> m_TaskQueue;
std::mutex m_Mutex;
std::condition_variable m_CV;
bool m_IsRunning;
int m_ThreadNum;
};
#endif
#include "ThreadPool.h"
static ThreadPool *pInstance = nullptr;
static std::once_flag flag1;
ThreadPool *ThreadPool::GetInstance(int number)
{
std::call_once(flag1, [number](){
pInstance = new ThreadPool(number);
});
return pInstance;
}
ThreadPool::ThreadPool(int number)
: m_ThreadNum(number), m_IsRunning(true)
{
m_Threads.push_back(std::thread([this](){
while (true) // thread keep alive
{
std::unique_lock<std::mutex> lock(m_Mutex);
m_CV.wait(lock, [this](){
bool isEmpty = m_TaskQueue.empty();
// task is not empty or thread stopped
return !isEmpty || !m_IsRunning;
});
if (!m_IsRunning)// thread stop
{
break;
}
auto task = m_TaskQueue.front();
m_TaskQueue.pop();
lock.unlock();
task();
}
}));
}
ThreadPool::~ThreadPool()
{
{
std::unique_lock<std::mutex> lock(m_Mutex);
m_IsRunning = false;
}
m_CV.notify_all();
for (auto &t : m_Threads)
{
if (t.joinable())
{
t.join();
}
}
}