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_OBJECT
public:
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_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
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_OBJECT
public:
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_OBJECT
public:
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_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
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)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/34584.html