c++实现线程池
本文将不会使用C++不易理解的特性,将使用最基本的c++语法实现一个线程对象以及线程池,
完整工程见:https://github.com/wk-xjd/wkthreadpool
自旋锁类
#ifndef WKLOCKER_H
#define WKLOCKER_H
#include <mutex>
#include <atomic>
#include <condition_variable>
class WKLocker
{
public:
WKLocker(int spinTimes = 20);
~WKLocker();
void lock();
void unlock();
private:
std::atomic<unsigned int> m_currentThreadId = 0;
std::condition_variable m_condition;
int m_lockCount = 0;
std::mutex m_muetex;
unsigned int m_exceptValue = 0;
int m_spinCount;
std::atomic<bool> m_delete = false;
};
#endif
#include "WKLocker.h"
#include "utils.h"
WKLocker::WKLocker(int spinTimes)
: m_spinCount(spinTimes)
{
}
WKLocker::~WKLocker()
{
m_delete = true;
m_condition.notify_all();
}
void WKLocker::lock()
{
unsigned int curThrId = WKUtils::currentThreadId();
START_GET_LOCK:
{
//自旋
std::atomic<int> currCount = m_spinCount;
while (!m_currentThreadId.compare_exchange_weak(m_exceptValue, curThrId))
{
if (!currCount.fetch_sub(1))
break;
}
//自旋失败获取锁失败则阻塞
if (m_currentThreadId == curThrId)
{
m_lockCount++; //重入
}
else
{
std::unique_lock<std::mutex> locker(m_muetex);
m_condition.wait(locker, [&]()
{return m_currentThreadId == m_exceptValue; });
locker.unlock();
//锁被让出后,重新获取锁
if (!m_delete)
goto START_GET_LOCK;
}
}
}
void WKLocker::unlock()
{
unsigned int curThrId = WKUtils::currentThreadId();
if (m_currentThreadId == curThrId)
{
if (!(--m_lockCount))
{
//锁释放后唤醒所有阻塞在该锁的线程
m_currentThreadId = m_exceptValue;
m_condition.notify_all();
m_lockCount = 0;
}
}
}
线程任务类
通过添加任务的方式启动在新线程中执行,则需要继承该线程任务类
#ifndef WKTHREAGTASK_H
#define WKTHREAGTASK_H
/*
线程任务基类(抽象类)
1.任务入口:重写纯虚函数run函数,
2.任务结束回调入口:重写虚函数callback函数
3.任务有三个优先级(PriortyLevel),默认为LOW,将任务添加到线程池任务队列时,会优先处理高优先级任务
4.getTaskId(虚函数可重写),默认使用实例对象的地址的hashcode
5.可以设置m_autoDelete属性,任务执行结束后是否自动释放该对象,若为ture,一定要重写析构函数
*/
class WKThreadTask
{
public:
enum PriortyLevel
{
Low,
Middle,
Hight,
};
WKThreadTask() {};
virtual ~WKThreadTask() {};
virtual void run() = 0;
virtual void callback() {};
virtual unsigned int getTaskId() { return hash_task_fn(this); }
PriortyLevel taskPriorty() { return m_priorty; }
void setTaskPriorty(PriortyLevel level) { m_priorty = level; }
bool isAutoDelete() { return m_autoDelete; } const
void setAutoDelete(const bool isAutoDeleted = false) { m_autoDelete = isAutoDeleted; }
private:
std::hash<WKThreadTask*> hash_task_fn;
unsigned int m_taskId = 0;
PriortyLevel m_priorty = PriortyLevel::Low;
bool m_autoDelete = false;
};
#endif //WKTHREAGTASK_H
线程类
#pragma once
#ifndef WKThread_H
#define WKThread_H
#include <thread>
#include <atomic>
#include <mutex>
#include <deque>
#include <condition_variable>
#include "WKLocker.h"
class WKThreadTask;
/*
WKThread线程类使用方式:
1.继承WKThread类,并重写run方法,
通过start方法启动线程并执行,线程执行完毕自动释放该线程
2.实例化WKThread对象,并将继承了WKThreadTask的线程任务添加到线程,
2.1 通过start方法启动线程,
2.2 线程任务执行完毕后,线程不会立即释放,
2.3 线程任务执行完毕后进入挂起状态,等待下一次添加任务唤醒
2.4 线程随实例化对象释放而释放,也可以通过quit方法释放线程
*/
class WKThread
{
public:
enum ThreadState
{
Running,
Finished,
Waiting,
};
WKThread();
virtual ~WKThread();
void start(); //启动线程
void quit(); //退出线程
void wake(); //唤醒线程
void wait(); //挂起线程
bool addTask(WKThreadTask* task); //添加线程任务,并唤醒线程,返回任务是否添加成功
void setNextTaskQueue(std::deque<WKThreadTask*>* nextTaskQueue); //传递一个任务队列,当前线程任务执行完毕后自动从任务队列中取任务
void removeNextTaskQueue(); //移除任务队列
const bool hasNextTaskQueue(); //是否有任务队列
WKThread* getInstance(); //获取当前线程对象地址
unsigned int getThreadId() const; //获取线程id
bool isRunning() const; //当前线程是否正在运行
bool isFinished() const; //线程任务是否执行完成
bool isWaiting() const; //线程是否处于挂起等待状态
protected:
virtual void run(); //线程执行(用户)任务入口,若该方法未被重写使用方式2创建线程任务,否则使用方式1
private:
void _runTask(); //通过std库获取到的线程入口
void _updateState(ThreadState state); //更新线程状态
private:
std::thread* m_stdThread = nullptr;
std::atomic<bool> m_bWaitFlag = false;
std::atomic<bool> m_bQuitFlag = true;
std::atomic<enum ThreadState> m_state = ThreadState::Waiting;
std::mutex m_mutex;
std::condition_variable m_condition;
unsigned int m_threadId = 0;
WKThreadTask* m_task = nullptr;
WKLocker m_wkLocker; //状态锁
WKLocker m_nextQueueWKLocker; //队列锁
std::deque<WKThreadTask*>* m_nextTaskQueue = nullptr;
};
#endif // WKThread_H
线程池类
#include <queue>
#include <thread>
#include <atomic>
#include <deque>
#include <mutex>
#include <condition_variable>
#include "WKLocker.h"
class WKThread;
class WKThreadTask;
/*
线程池
1.懒创建线程,有任务且线程数小于最大线程数时创建新的线程
2.动态调整轮询检查线程状态的间隔
*/
class WKThreadPool
{
public:
WKThreadPool();
WKThreadPool(int maxThreadSize, int maxTaskSize);
~WKThreadPool();
void start(); //启动线程池
void stop(); //停止线程池,停止加入任务
bool isStop() const; //线程池是否被终止
bool addTask(WKThreadTask* task); //添加任务,返回任务添加结果
int waitThreadCount() const; //挂起等待线程数
int doneThreadCount() const; //运行工作线程数
int maxThreadSize() const; //最大线程数
int maxTaskSize() const; //最大任务队列最大任务数
int currentTaskSize() const; //当前任务数
private:
void _benginScheduler(); //调度管理
void _createThread(); //创建一个新的线程
void _checkThreadQueue(); //检查线程运行情况,将空闲线程置于空闲线程队列中
void _stopAllThread(); //停止加入新任务,执行完队列中的任务
void _sleepIntrval(const int ms); //调度间隔
WKThreadTask* _getTask(); //取一个队首任务
void _updateElasticInterval(); // 更新弹性的检查间隔,工作线程增多则间隔检查间隔减少,否则增加
private:
std::thread* m_pollingThread = nullptr;
std::deque<WKThreadTask*> m_taskQueue;
std::queue<WKThread*> m_threadDoneQueue;
std::queue<WKThread*> m_threadWaitQueue;
std::atomic<bool> m_bStoped = true;
std::atomic<int> m_threadDoneCount = 0;
std::atomic<int> m_threadWaitCount = 0;
std::atomic<int> m_taskCount = 0;
int m_maxThreadSize = 0;
int m_maxTaskSize = 30;
std::atomic<bool> m_bExiting = false;
std::condition_variable m_condition;
std::mutex m_mutex;
int m_lastWaitThreadcount = 0;
int m_waitThreadCountGradient = 0;
int m_sleepIntrval = 0;
WKLocker m_threadQueueWKLocker;
};