Qt本身就具备线程池类QThreadPool,使用起来也很方便,不过现在我们用QThread来做一个自己的线程池。
创建用来管理线程池的类ThreadPool,在这里它发挥着管家的职责,掌管公共资源的使用。由于管理任务的队列、锁以及条件变量都声明了私有,所以给WorkThread声明为友元类,以便其能访问。
为了简单,我们只定义了一个构造函数以及三个函数:
ThreadPool(int count,QObject*parent=nullptr) 其中count表示要在线程池中创建多少个子线程
关于子线程的管理我们使用的智能指针,以方便资源自动释放。下面就是ThreadPool的实现:
//头文件
//线程池
class ThreadPool : public QObject
{
Q_OBJECT
public:
explicit ThreadPool(int count,QObject *parent = nullptr);
~ThreadPool();
void PushTask(Task);
void Start();
void Destroy();
private:
QList m_Tasks; // 任务队列
QList> m_Threads; //运行的线程
bool m_bStop; //停止线程
QMutex m_TaskMutex;
QWaitCondition m_NotEmpty;
friend class WorkThread;
};
//实现
ThreadPool::ThreadPool(int count,QObject *parent) : QObject(parent),m_bStop(false)
{
for(int i=0;i(new WorkThread(this)));
}
ThreadPool::~ThreadPool()
{
Destroy();
}
void ThreadPool::PushTask(Task task)
{
m_TaskMutex.lock();
m_Tasks.push_back(task);
m_NotEmpty.wakeOne();
m_TaskMutex.unlock();
}
void ThreadPool::Start()
{
foreach (auto thread, m_Threads)
{
thread->start();
}
}
void ThreadPool::Destroy()
{
m_bStop = true;
m_NotEmpty.wakeAll();
//等待线程退出
foreach (auto thread, m_Threads)
{
if(!thread->isFinished())
thread->wait();
}
//清空 智能指针自动释放
m_Threads.clear();
}
以WorkThread做为线程池中的子线程,所以要继承QThread,并重新实现run()函数。
由于公共资源都在ThreadPool中,所以我们定义了一个父类指针m_Pool来使用公共资源。
还定义了 m_Handle,主要为了下析构时打印线程ID,关于这块大家可以参考我以前测试的一个例子https://blog.csdn.net/hanzhaoqiao1436/article/details/80957945
实现如下:
//头文件
//执行线程
class WorkThread:public QThread
{
public:
WorkThread(ThreadPool* parent);
~WorkThread();
protected:
virtual void run();
private:
ThreadPool* m_Pool;
Qt::HANDLE m_Handle;
};
//实现
WorkThread::WorkThread(ThreadPool *parent)
{
m_Pool = parent;
}
WorkThread::~WorkThread()
{
qDebug() << __FUNCTION__ << m_Handle << "Thread quit: " << isFinished();
}
void WorkThread::run()
{
m_Handle = QThread::currentThreadId();
while(!m_Pool->m_bStop)
{
m_Pool->m_TaskMutex.lock();
while(m_Pool->m_Tasks.isEmpty())
{
qDebug() << QThread::currentThreadId() << QString::fromLocal8Bit("进入等待");
m_Pool->m_NotEmpty.wait(&m_Pool->m_TaskMutex);
qDebug() << QThread::currentThreadId() << QString::fromLocal8Bit("被唤醒");
//线程退出条件判断
if(m_Pool->m_bStop)
{
m_Pool->m_TaskMutex.unlock();
return;
}
}
//取出任务
Task task = m_Pool->m_Tasks.front();
m_Pool->m_Tasks.pop_front();
m_Pool->m_TaskMutex.unlock();
if(task)
{
//执行任务
task();
}
}
}
差点忘了贴函数对象Task的定义-_-|| I'm sorry
//任务类型
class Task
{
public:
Task(int a,int b):m_a(a),m_b(b){}
void operator ()()const
{
QThread::msleep(300);
qDebug() << QThread::currentThreadId() << QString::fromLocal8Bit("执行任务") << m_a << "+" << m_b << "=" << m_a+m_b;
}
operator bool() const
{
//如果做除法这里可以判断下
if(m_b == 0)
return false;
return true;
}
private:
int m_a,m_b;
};
调用测试:
//创建三个子线程
m_Pool(new ThreadPool(3,this));
//直接启动线程
m_Pool->Start();
//此时能看到所有线程都进入等待状态
QThread::msleep(100);
//添加任务
for(int i=0;i<4;i++)
{
m_Pool->PushTask(Task(qrand(),qrand()));
}
运行结果:
0x17fc "进入等待"
0x1990 "进入等待"
0x1298 "进入等待"
0x1298 "被唤醒"
0x1990 "被唤醒"
0x17fc "被唤醒"
0x1990 "执行任务" 26500 + 6334 = 32834
0x1298 "执行任务" 18467 + 41 = 18508
0x17fc "执行任务" 15724 + 19169 = 34893
0x1298 "进入等待"
0x17fc "进入等待"
0x1990 "执行任务" 29358 + 11478 = 40836
0x1990 "进入等待"
(调用Destroy)
0x1298 "被唤醒"
0x17fc "被唤醒"
0x1990 "被唤醒"
~WorkThread 0x1298 Thread quit: true
~WorkThread 0x1990 Thread quit: true
~WorkThread 0x17fc Thread quit: true
假如我们在Destroy()中,不停止直接释放子线程,线程会自动停下来吗?答案当然是否定的。比如说我们注释掉停止的相关调用
void ThreadPool::Destroy()
{
//m_bStop = true;
//m_NotEmpty.wakeAll();
//等待线程退出
//foreach (auto thread, m_Threads)
//{
// if(!thread->isFinished())
// thread->wait();
//}
//清空 智能指针自动释放
m_Threads.clear();
}
(会看到如下结果)
~WorkThread 0x1958 Thread quit: false
QThread: Destroyed while thread is still running
(附上程序源码,欢迎大家指点错误)