上一篇文章中提到在QT中使用线程类QThread,但是QT中还有一个同样可以实现多线程那就是QRunable,这个QT提供的轻量级的线程处理机制,关于QRunable的使用可以详见我这篇文章Qt 线程池的使用以及和主线程的消息同步。
QRunable可以通过线程池来控制,QThreadPool线程池是一个全局的单例模式,使用也是比较方便的,但是如何检测同时运行的QRunable线程结束了呢?有的同学会说可以使用waitForDone线程池提供的函数来实现:
waitForDone
Waits up to msecs milliseconds for all threads to exit and removes all threads from the thread pool. Returns true if all threads were removed; otherwise it returns false. If msecs is -1 (the default), the timeout is ignored (waits for the last thread to exit).
自定义一个QRunnable的子类
#pragma once
#include <QRunnable>
#include "ILoadData.h"
class QtLoadRunable : public QRunnable {
public:
QtLoadRunable(ILoadData *load);
~QtLoadRunable();
virtual void run();
private:
ILoadData* _loadData = nullptr;
};
#include "QtLoadRunable.h"
QtLoadRunable::QtLoadRunable(ILoadData *load){
_loadData = load;
}
QtLoadRunable::~QtLoadRunable() {
}
void QtLoadRunable::run() {
_loadData->loadData();
}
继续使用上一篇文章中的ILoadData接口,然后定义一个界面类,使其继承这个接口类,并且实现这个接口函数:
void MyThread::loadData() {
while (true) {
QThread::msleep(1000);
count++;
qDebug() << QStringLiteral("线程运行中...... ")<< count;
}
}
然后启动这个线程调用接口:
void MyThread::slotThread() {
QtLoadRunable* runnable = new QtLoadRunable(this);
QThreadPool::globalInstance()->start(runnable);
QThreadPool::globalInstance()->waitForDone();
qDebug() << QStringLiteral("线程运行完成!");
}
然后运行程序,不断的打印出信息,但是界面不在接受任何鼠标或者键盘的操作,程序就卡住了,出现了假死:
调用waitForDone这个函数会阻塞主线程的,使整个程序处于“假死”的状态,那么如何检测到所有的线程运行完成,又不会阻塞主线程呢?
可以定义一个线程计数器,初始化会记录开启的线程数,每当一个线程运行完成的后,计数器就会加1,当计数器的数量等于初始化的数量时,表示所有的线程已经运行完成了。
首先定义三个加载数据的类,分别继承加载接口:
第一个:
#pragma once
#include "ILoadData.h"
class LoadData1 :public ILoadData {
public:
LoadData1();
~LoadData1();
virtual void loadData()override;
};
#include "LoadData1.h"
#include <QThread>
LoadData1::LoadData1() {
}
LoadData1::~LoadData1() {
}
void LoadData1::loadData() {
QThread::msleep(1000);
}
第二个:
#pragma once
#include "ILoadData.h"
class LoadData2 :public ILoadData {
public:
LoadData2();
~LoadData2();
virtual void loadData()override;
};
#include "LoadData2.h"
#include <QThread>
LoadData2::LoadData2() {
}
LoadData2::~LoadData2() {
}
void LoadData2::loadData() {
QThread::msleep(2000);
}
第三个:
#pragma once
#include "ILoadData.h"
class LoadData3 :public ILoadData {
public:
LoadData3();
~LoadData3();
virtual void loadData()override;
};
#include "LoadData3.h"
#include <QThread>
LoadData3::LoadData3() {
}
LoadData3::~LoadData3() {
}
void LoadData3::loadData() {
QThread::msleep(3000);
}
定义线程计数器管理类,为了方便使用,这个类使用单例模式:
#pragma once
#include <QMutex>
#define RunCntInst() (RunCount::getInstance())
class RunCount {
private:
RunCount();
static RunCount* _instance;
public:
~RunCount();
static RunCount* getInstance();
//设置运行的总线程数
void totalRunable(int total);
//每次运行完成就调用这个函数,使线程计数器+1
void finished();
private:
int _totalRunable = 0;//总共启动的线程数
int _finishedRunable = 0;//已经运行完成的线程数
QMutex mutex;//线程锁
};
#include "RunCount.h"
#include <QDebug>
RunCount* RunCount::_instance = new RunCount;
RunCount::RunCount() {
}
RunCount::~RunCount() {
}
RunCount* RunCount::getInstance() {
return _instance;
}
void RunCount::totalRunable(int total) {
_totalRunable = total;
}
void RunCount::finished() {
mutex.lock();//加锁锁定,防止多个线程同时使用这部分
_finishedRunable++;
if (_finishedRunable == _totalRunable){
qDebug() << QStringLiteral("线程运行完成!");
}
mutex.unlock();
}
调用:
void MyThread::slotThread() {
RunCntInst()->totalRunable(3);
LoadData1* load1 = new LoadData1;
QtLoadRunable* runnable1 = new QtLoadRunable(load1);
QThreadPool::globalInstance()->start(runnable1);
LoadData2* load2 = new LoadData2;
QtLoadRunable* runnable2 = new QtLoadRunable(load2);
QThreadPool::globalInstance()->start(runnable2);
LoadData3* load3 = new LoadData3;
QtLoadRunable* runnable3 = new QtLoadRunable(load3);
QThreadPool::globalInstance()->start(runnable3);
}
运行结果: