多线程一般用在:
在QT的 UI 编程中, 如果有一个函数消耗的时间特别长, 并且运行于主线程, 那么界面的响应会很不灵敏.。比如说 如果该函数执行时间很长, 为了通知任务的进度, 一般会使用进度条. 但有时候无法准确的使用进度条, 比如在数据库操作中, 为了提高读写数据库的性能, 通常会采用事务操作, 多个读写数据库的操作合并成了一个事务, 此时如何设置进度条的进度值。
Qt 多线程常见得三种方法:
1. 继承自QThread.
2. moveToThread.
3. QtConcurrent::run().
MyThread
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include
#include
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject* parent = nullptr);
~MyThread();
signals:
void SigMyThread(int para);
public slots:
void onMyThread(int para);
protected:
void run() override;
};
#endif // MYTHREAD_H
#include "mythread.h"
#include
MyThread::MyThread(QObject* parent)
:QThread (parent)
{
}
MyThread::~MyThread()
{
}
void MyThread::onMyThread(int para)
{
qDebug()<< __FUNCTION__ <<"current thread ID:"<<QThread::currentThreadId();
int count = 888;
for(int i = 0;i!=1000000;++i)
{
++count;
}
}
void MyThread::run()
{
qDebug()<< __FUNCTION__ <<"current thread ID:"<<QThread::currentThreadId();
int count = 0;
for(int i = 0;i!=1000000;++i)
{
++count;
}
emit SigMyThread(count);
exec();
}
Controller
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include
#include
#include "mythread.h"
class Controller : public QObject
{
Q_OBJECT
public:
explicit Controller(QObject *parent = nullptr);
~Controller();
signals:
void sigOperate( int para);
public slots:
void onHandleResult( int result);
private:
QThread m_WorkerThread;
MyThread* m_pMyThread = nullptr;
};
#endif // CONTROLLER_H
#include "controller.h"
#include
#include "worker.h"
Controller::Controller(QObject *parent)
: QObject(parent)
{
#if 0
Worker *worker = new Worker;
worker->moveToThread(&m_pWorkerThread); //调用moveToThread将该任务交给workThread
connect(this, SIGNAL(sigOperate(int)), worker, SLOT(onDoWork(int))); //operate信号发射后启动线程工作
connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); //该线程结束时销毁
connect(worker, SIGNAL(sigResultReady(int)), this, SLOT(onHandleResult(int))); //线程结束后发送信号,对结果进行处理
m_pWorkerThread.start(); //启动线程
qDebug()<<__FUNCTION__<<"current thread ID:"<<QThread::currentThreadId();
emit sigOperate(0);
#endif
m_pMyThread = new MyThread;
connect(m_pMyThread,&MyThread::SigMyThread,this,&Controller::onHandleResult);
connect(m_pMyThread, &QThread::finished, this, &QObject::deleteLater); //该线程结束时销毁
connect(this,&Controller::sigOperate,m_pMyThread,&MyThread::onMyThread);
m_pMyThread->start();
m_pMyThread->sleep(3);
qDebug()<<__FUNCTION__<<"current thread ID:"<<QThread::currentThreadId();
// QThread::sleep(5); 延迟5s 所有线程阻塞
emit sigOperate(999);
}
Controller::~Controller()
{
#if 0
m_pWorkerThread.quit();
m_pWorkerThread.wait();
#endif
m_pMyThread->quit();
m_pMyThread->wait();
}
void Controller::onHandleResult( int result)
{
qDebug() << __FUNCTION__ <<"current ID :" <<QThread::currentThreadId();
qDebug() << "the result is " <<result;
}
main.cpp
#include "mainwindow.h"
#include
#include "controller.h"
#include
#include
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Controller controller;
QTime dieTime = QTime::currentTime().addMSecs(1);
while( QTime::currentTime() < dieTime)
QCoreApplication::processEvents(QEventLoop::AllEvents, 100);
qDebug() << "main CurrentID :" << QThread::currentThreadId();
return a.exec();
}
worker
#ifndef WORKER_H
#define WORKER_H
#include
class Worker : public QObject
{
Q_OBJECT
public:
explicit Worker(QObject *parent = nullptr);
~Worker();
signals:
void sigResultReady(int result);
public slots:
void onDoWork(int para);
};
#endif // WORKER_H
#include "worker.h"
#include
#include
Worker::Worker(QObject *parent)
: QObject(parent)
{
}
Worker::~Worker()
{
}
void Worker::onDoWork(int para)
{
qDebug()<<__FUNCTION__<< "current ID :" << QThread::currentThreadId();
for(int i = 0; i != 1000000; ++i)
{
++para;
}
emit sigResultReady(para);
}
Controller
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include
#include
#include "mythread.h"
class Controller : public QObject
{
Q_OBJECT
public:
explicit Controller(QObject *parent = nullptr);
~Controller();
signals:
void sigOperate( int para);
public slots:
void onHandleResult( int result);
private:
QThread m_WorkerThread;
MyThread* m_pMyThread = nullptr;
};
#endif // CONTROLLER_H
#include "controller.h"
#include
#include "worker.h"
Controller::Controller(QObject *parent)
: QObject(parent)
{
#if 1
Worker *worker = new Worker;
worker->moveToThread(&m_WorkerThread); //调用moveToThread将该任务交给workThread
connect(this, SIGNAL(sigOperate(int)), worker, SLOT(onDoWork(int))); //operate信号发射后启动线程工作
connect(&m_WorkerThread, &QThread::finished, worker, &QObject::deleteLater); //该线程结束时销毁
connect(worker, SIGNAL(sigResultReady(int)), this, SLOT(onHandleResult(int))); //线程结束后发送信号,对结果进行处理
m_WorkerThread.start(); //启动线程
qDebug()<<__FUNCTION__<<"current thread ID:"<<QThread::currentThreadId();
emit sigOperate(0);
#endif
#if 0
m_pMyThread = new MyThread;
connect(m_pMyThread,&MyThread::SigMyThread,this,&Controller::onHandleResult);
connect(m_pMyThread, &QThread::finished, this, &QObject::deleteLater); //该线程结束时销毁
connect(this,&Controller::sigOperate,m_pMyThread,&MyThread::onMyThread);
m_pMyThread->start();
m_pMyThread->sleep(3);
qDebug()<<__FUNCTION__<<"current thread ID:"<<QThread::currentThreadId();
// QThread::sleep(5); 延迟5s 所有线程阻塞
emit sigOperate(999);
#endif
}
Controller::~Controller()
{
#if 0
m_pWorkerThread.quit();
m_pWorkerThread.wait();
#endif
m_pMyThread->quit();
m_pMyThread->wait();
}
void Controller::onHandleResult( int result)
{
qDebug() << __FUNCTION__ <<"current ID :" <<QThread::currentThreadId();
qDebug() << "the result is " <<result;
}
main
#include "mainwindow.h"
#include
#include "controller.h"
#include
#include
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
#if 1
Controller controller;
qDebug() << "main CurrentID :" << QThread::currentThreadId();
#endif
return a.exec();
}
需要了解如下类 :
QtConcurrent 是一个名字空间, 其内包含了众多的高级 API, 方便用户编写多线程程序.
QFutureWatcher 可以用于监视线程的完成情况, 并获取线程的返回值.
QtConcurrent 线程函数与 QFutureWatcher 之间的中间者是 QFuture.
mainwindow
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include
#include
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
void busyJob();
private:
int doBusyJob();
void busyJobFinished();
private:
Ui::MainWindow *ui;
QFutureWatcher* m_pWatch = nullptr;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
#include
#include
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_pWatch = new QFutureWatcher<int>;
connect(m_pWatch, &QFutureWatcher<int>::finished,
this, &MainWindow::busyJobFinished);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::busyJob()
{
qDebug()<<__FUNCTION__<<"current thread ID:"<<QThread::currentThreadId();
auto future = QtConcurrent::run(this, &MainWindow::doBusyJob);
m_pWatch->setFuture(future);
}
int MainWindow::doBusyJob()
{
qDebug()<<__FUNCTION__<<"current thread ID:"<<QThread::currentThreadId();
return 1;
}
void MainWindow::busyJobFinished()
{
qDebug()<<__FUNCTION__<<"current thread ID:"<<QThread::currentThreadId();
qDebug()<<__FUNCTION__<< "the returned value is: "
<< m_pWatch->result();
}
main
#include "mainwindow.h"
#include
#include "controller.h"
#include
#include
#include
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
#if 1
MainWindow w;
qDebug()<<__FUNCTION__<<"current thread ID:"<
moveToThread方法,是把我们需要的工作全部封装在一个类中,将每个任务定义为一个的槽函数,再建立触发这些槽的信号,然后把信号和槽连接起来,最后将这个类调用moveToThread方法交给一个QThread对象,再调用QThread的start()函数使其全权处理事件循环。于是,任何时候我们需要让线程执行某个任务,只需要发出对应的信号就可以。其优点是我们可以在一个worker类中定义很多个需要做的工作,然后发出触发的信号线程就可以执行。相比于子类化的QThread只能执行run()函数中的任务,moveToThread的方法中一个线程可以做很多不同的工作(只要发出任务的对应的信号即可)。
子类化QThread的方法,就是重写了QThread中的run()函数,在run()函数中定义了需要的工作。这样的结果是,我们自定义的子线程调用start()函数后,便开始执行run()函数。如果在自定义的线程类中定义相关槽函数,那么这些槽函数不会由子类化的QThread自身事件循环所执行,而是由该子线程的拥有者所在线程(一般都是主线程)来执行。如果你不明白的话,请看,第二个例子中,子类化的线程的槽函数中输出当前线程的ID,而这个ID居然是主线程的ID!!事实的确是如此,子类化的QThread只能执行run()函数中的任务直到run()函数退出,而它的槽函数根本不会被自己的线程执行。
借鉴大神网址:
https://blog.csdn.net/qq_38410730/article/details/80783902
https://blog.csdn.net/ding_yingzi/article/details/80692099
主要是弄懂大神想法,自己动手敲代码弄清楚。如有侵权,请联系我更改。