QT多线程信号槽使用

一、前言

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开发必备技术栈学习路线和资料

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值