Qt 多线程(QThread)
一.理解QThread
关于QThread,参考qt助手中的解析
Detailed Description
A QThread object manages one thread of control within the program. QThreads begin executing in run(). By default, run() starts the event loop by calling exec() and runs a Qt event loop inside the thread.
You can use worker objects by moving them to the thread using QObject::moveToThread().
(详细说明
QThread对象管理程序中的一个控制线程。QThreads开始在run()中执行。默认情况下,run()通过调用exec()启动事件循环,并在线程内运行Qt事件循环。
您可以通过使用QObject::moveToThread()将辅助对象移动到线程来使用它们。)
注意:实际上,QThread可以理解为线程控制器,它本身并不是一个线程,只是QThread管理了一个线程而已。
实际上,继承自QThread的类中,下面两种情况的代码才是运行在次线程中。
(1).run()函数的代码。
(2).次线程执行exec()函数,开启事件循环。某个继承自QObject的类obj,通过moveToThread()函数移入次线程,
并且通过信号槽机制触发obj的槽函数(信号槽连接方式不能为 Qt::DirectConnection)
二.QThread的使用方法。
方法1:新建一个类,继承类QThread,重载run()函数,并将关键代码放到run()中执行。执行完成后,发送信号,告诉主线程完成。
//workerthread.h
#ifndef WORKERTHREAD_H
#define WORKERTHREAD_H
#include <QThread>class WorkerThread : public QThread
{Q_OBJECTpublic:WorkerThread(QObject *parent = nullptr);protected:void run();signals:void sigResult();
};#endif // WORKERTHREAD_H
//workerthread.cpp
#include "workerthread.h"
#include <QDebug>WorkerThread::WorkerThread(QObject *parent):QThread(parent)
{}void WorkerThread::run()
{/*死循环,让线程一直跑。或者处理完毕就退出*/qDebug()<<"WorkerThread run: threadId: "<<QThread::currentThreadId();emit sigResult();
}
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "myThread1.h"QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:Ui::MainWindow *ui;private slots:void slotResult();void slotResultQueued();void slotResultDirect();};
#endif // MAINWINDOW_H
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>
#include <QDebug>
#include <workerthread.h>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);qDebug()<<"main threadId: "<<QThread::currentThreadId();WorkerThread *workthread = new WorkerThread(this);//匿名槽函数,槽函数运行在次线程connect(workthread, &WorkerThread::sigResult, [=](){qDebug()<<"lanba slot threadId: "<<QThread::currentThreadId();});//普通连接方式,槽函数运行在主线程connect(workthread, &WorkerThread::sigResult, this, &MainWindow::slotResult);//队列连接connect(workthread, &WorkerThread::sigResult, this, &MainWindow::slotResultQueued, Qt::QueuedConnection);//直接连接connect(workthread, &WorkerThread::sigResult, this, &MainWindow::slotResultDirect, Qt::DirectConnection);workthread->start();
}MainWindow::~MainWindow()
{delete ui;
}//普通连接方式的槽函数
void MainWindow::slotResult()
{qDebug()<<"slotResult threadId: "<<QThread::currentThreadId();
}//队列连接方式的槽函数
void MainWindow::slotResultQueued()
{qDebug()<<"slotResultQueued threadId: "<<QThread::currentThreadId();
}//直接连接方式的槽函数
void MainWindow::slotResultDirect()
{qDebug()<<"slotResultDirect threadId: "<<QThread::currentThreadId();
}
运行结果:

结论:
使用上述方式调用线程槽函数所在的线程如下:
1.槽函数为匿名函数,槽函数运行在发送者所在的线程。
2.采用Qt::DirectConnection方式连接信号槽,槽函数运行在发送者所在的线程。
3.其它连接方式,槽函数运行在接受者所在的线程。
方法2:次线程在run()函数中执行exec()函数,开启事件循环。某个继承自QObject的类obj,通过moveToThread()函数移入次线程,
并且通过信号槽机制触发obj的槽函数(信号槽连接方式不能为 Qt::DirectConnection)
//workerThread.h
#ifndef WORKERTHREAD_H
#define WORKERTHREAD_H
#include <QThread>class WorkerThread : public QThread
{Q_OBJECTpublic:WorkerThread(QObject *parent = nullptr);protected:void run();
};
//workerThread.cpp
#include "workerthread.h"
#include <QDebug>WorkerThread::WorkerThread(QObject *parent):QThread(parent)
{}void WorkerThread::run()
{qDebug()<<"WorkerThread run: threadId: "<<QThread::currentThreadId();exec(); //执行exec()函数,开启事件循环
}
//worker.h
#ifndef WORKER_H
#define WORKER_H#include <QObject>class Worker : public QObject
{Q_OBJECTpublic:explicit Worker(QObject *parent = nullptr);signals:void sigFinished();public slots:void doSomething();
};#endif // WORKER_H
//worker.cpp
#include "worker.h"
#include <QThread>
#include <QDebug>Worker::Worker(QObject *parent) :QObject(parent)
{}void Worker::doSomething()
{qDebug()<<"worker doSomething: threadId: "<<QThread::currentThreadId();emit sigFinished();
}
//mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include "myThread1.h"QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();private:Ui::MainWindow *ui;signals:void sigDoSomething();private slots:void slotFinished();void slotFinishedQueued();void slotFinishedDirect();};
#endif // MAINWINDOW_H
//mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThread>
#include <QDebug>
#include <workerthread.h>
#include <worker.h>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);qDebug()<<"main threadId: "<<QThread::currentThreadId();WorkerThread *workthread = new WorkerThread(this);Worker *worker = new Worker(); //不能设置父类worker->moveToThread(workthread); //将worker 移动到 次线程//主线程发送信号,次线程接收信号,槽函数运行在接受者线程。connect(this, &MainWindow::sigDoSomething, worker, &Worker::doSomething);//匿名函数connect(worker, &Worker::sigFinished, [=](){qDebug()<<"lanba slot threadId: "<<QThread::currentThreadId();});//普通连接方式,槽函数运行在接受者线程connect(worker, &Worker::sigFinished, this, &MainWindow::slotFinished);//队列连接,槽函数运行在接受者线程connect(worker, &Worker::sigFinished, this, &MainWindow::slotFinishedQueued, Qt::QueuedConnection);//直接连接,槽函数运行在发送者所在线程。connect(worker, &Worker::sigFinished, this, &MainWindow::slotFinishedDirect, Qt::DirectConnection);workthread->start();emit sigDoSomething();}MainWindow::~MainWindow()
{delete ui;
}//普通连接方式的槽函数
void MainWindow::slotFinished()
{qDebug()<<"slotFinished threadId: "<<QThread::currentThreadId();
}//队列连接方式的槽函数
void MainWindow::slotFinishedQueued()
{qDebug()<<"slotFinishedQueued threadId: "<<QThread::currentThreadId();
}//直接连接方式的槽函数
void MainWindow::slotFinishedDirect()
{qDebug()<<"slotFinishedDirect threadId: "<<QThread::currentThreadId();
}
//运行 结果

结论,通过moveToThread()方式,确实可以将槽函数运行在次线程(信号槽连接方式不能为:Qt::DirectConnection)


















