QT多线程信号槽使用
2023-09-14 09:05:12 时间
一、前言
QT的信号槽在多线程环境下经常有人遇到信号槽连接后执行有问题,或者直接不执行,所以新版推荐大家使用QObject::moveToThread方法来实现多线程连接信号槽,实际测试表示这种方法非常实用,但是写的代码就增加一些,还容易弄错,也没有彻底理解为什么,今天就来谈谈并且做一个封装
二、QT多线程信号槽机制
QT的槽函数执行线程决定于宿主对象所在线程而无关信号发出线程,这也是moveToThread的根本所在,就是将宿主对象移到线程内,这样槽函数的执行权才能在线程内。
而有些小伙伴用传统继承QThread的方法,在线程内部创建对象连接信号槽后,连槽函数都没有得到执行,追根溯源是因为虽然宿主对象在线程内,但是线程没有事件循环,而QT的信号槽是依赖事件循环来执行的,这时候就需要在run函数内执行exec函数,便可以开启QThread的事件循环。
三、例子
main 0x6a18
todo start 0x1f00
todo end 0x1f00
todo Print 0x6a18
todo start 0x1f00
todo end 0x1f00
todo Print 0x6a18
todo start 0x1f00
todo end 0x1f00
todo Print 0x6a18
.h
#include "YThreadObject.h"
class Thread : public YThreadObject
{
Q_OBJECT
public:
explicit inline Thread(QObject* parent = nullptr): YThreadObject(parent) {}
signals:
void finished();
public slots:
void todo();
};
void Thread::todo()
{
qDebug() << __func__ << "start" << QThread::currentThreadId();
std::this_thread::sleep_for(std::chrono::seconds(1));
qDebug() << __func__ << "end" << QThread::currentThreadId();
emit finished();
}
class Print : public QObject
{
Q_OBJECT
public:
explicit inline Print(QObject* parent = nullptr): QObject(parent) {}
public slots:
void todo();
};
void Print::todo()
{
qDebug() << __func__ << "Print" << QThread::currentThreadId();
}
.cpp
int main(int argc, char* argv[])
{
QApplication application(argc, argv);
Thread thread;
Print print;
QTimer timer;
timer.connect(&timer, &QTimer::timeout, &thread, &Thread::todo);
timer.connect(&thread, &Thread::finished, &print, &Print::todo);
timer.connect(&timer, &QTimer::timeout, [&timer]{
static int index = 0;
++index;
if(index >= 5) timer.stop();
});
timer.start(2000);
qDebug() << __func__ << QThread::currentThreadId();
return application.exec();
}
四、QObject::moveToThread的封装
.h
#ifndef YTHREADOBJECT_H
#define YTHREADOBJECT_H
#include <QObject>
class QThread;
class YThreadObjectParasitic;
class YThreadObject : public QObject
{
Q_OBJECT
public:
explicit YThreadObject(QObject *parent = nullptr);
~YThreadObject();
bool wait(unsigned long time = ULONG_MAX);
signals:
public slots:
public:
QThread* thread = nullptr;
YThreadObjectParasitic* parasitic = nullptr;
};
#endif // YTHREADOBJECT_H
.cpp
#include "YThreadObject.h"
#include <QThread>
class YThreadObjectParasitic : public QObject
{
public:
explicit YThreadObjectParasitic(QObject *parent, YThreadObject* object) :
QObject(parent), object(object), currentThreadId(QThread::currentThreadId()){}
~YThreadObjectParasitic() {
if(object){
YThreadObject* tobject = object;
object = nullptr;
delete tobject;
}
}
YThreadObject* object = nullptr;
Qt::HANDLE currentThreadId;
};
YThreadObject::YThreadObject(QObject *parent) : QObject(nullptr), parasitic(new YThreadObjectParasitic(parent, this))
{
thread = new QThread;
moveToThread(thread);
thread->start();
connect(thread, &QThread::finished, thread, &QThread::deleteLater);
}
YThreadObject::~YThreadObject()
{
if(thread){
thread->quit();
if(parasitic->currentThreadId == QThread::currentThreadId()){
thread->wait();
}
thread = nullptr;
}
if(parasitic->object){
parasitic->setParent(nullptr);
parasitic->object = nullptr;
parasitic->deleteLater();
parasitic = nullptr;
}
}
bool YThreadObject::wait(unsigned long time)
{
if(thread){
return thread->wait(time);
}
return true;
}
QT技术文档推荐:Qt开发必备技术栈学习路线和资料
相关文章
- Qt开发笔记之QCustomPlot:QCustomPlot介绍、编译与使用
- ubuntu安装qt运行环境_qt5安装教程
- mfc控件工具栏怎么打开_Qt界面库
- C/C++ Qt QChart 绘图组件应用
- C/C++ Qt 自定义Dialog对话框组件应用
- Qt开源网络库[8]-上传文件与超时处理
- Linux系统使用Qt开发快速入门教程(linux下qt教程)
- Qt迭代器(Java类型和STL类型)详解
- 使用Qt框架轻松连接MySQL数据库(qt与mysql连接)
- Linux 下 Qt 调试技巧(qt调试linux)
- 快速搭建 Qt 与 MySQL 的数据库应用(qt使用mysql)
- Linux Qt 论坛:探索开源GUI开发的无限可能(linuxqt论坛)
- Qt连接Oracle数据库的驱动问题(qtoracle驱动)
- 利用Linux系统和QT技术实现高效嵌入式应用程序开发(linux嵌入式qt)
- 加速Linux应用开发——QT开发技巧大揭秘(qtlinux开发)
- 深入浅出:使用Qt连接MSSQL(qt 连接mssql)
- Qt实现MySQL数据库操作详解(qt操作mysql数据库)
- 在Qt中编译Oracle环境(qt编译 oracle)