关于QT信号槽机制的第五个参数

关于QT信号槽机制的第五个参数

之前有关注过这个第五个参数的内容,但由于平时使用过程中都默认不写,也没特别仔细研究,直到今天一个同事问我,才仔细研究了一下含义。
其实网上有很多有关博客,讲解的内容也都很正确,但是就是没那么好理解,如下图所示,参考文章

在这里插入图片描述

其实里面最主要的4种方式有:Qt::AutoConnection(自动),Qt::DirectConnection(同步),Qt::QueuedConnection(异步),Qt::BlockingQueuedConnection(阻塞连接)。

第五个参数实际意义

通过阅读别人的博客,可以理解到,其实第五个参数控制的是,你原本想在子线程执行的逻辑到底在哪执行,虽然听起来很绕,但是QT确实允许你将子线程的任务挪到主线程去执行。

多线程信号和槽

个人认为,抛开QT的多线程单独去谈信号和槽的第五个参数是完全不合理的,因为第五个参数的使用与多线程的工作模式息息相关。
在QT中,多线程的写法一般有2种,早先的QT是通过创建一个继承了Qthread的类使用,而在较新的QT中则是采用movetothread的方式去实现的,而信号和槽的五个参数影响的则是通过movetothread实现的多线程工作方式,意识到这点至关重要,因为我就是在早期QT的多线程写法中去理解第五个参数,怎么试都没有得到逍遥的结果TAT。

新旧多线程对比

旧版多线程

我们以Qt::QueuedConnection举个例子,如果按照别的博客上的说法,Qt::QueuedConnection让槽函数运行于信号接受者所在线程,为了验证这个功能,我们进行如下设计。
我们设计一个按钮,按钮发送信号,这个信号同时连接本线程内的一个槽函数和其他线程的一个槽函数,相当于同一个信号挂到两个槽:

  connect(this,SIGNAL(ButtonSend(int)),thread,SLOT(ButtonReceive(int)),Qt::QueuedConnection);
  connect(this,SIGNAL(ButtonSend(int)),this,SLOT(ButtonReceive2(int)));

本线程的信号函数名称为ButtonSend,通过按钮点击实现:

void MainWindow::on_pushButton_clicked()
{
    emit ButtonSend(++i);
}

子线程的槽函数名称为ButtonReceive,我们让他sleep 2秒,实现方式为:

void MThread::ButtonReceive(int i )
{
    qDebug()<<"i am son , i got "<<i;
    qDebug()<<"sleeping...";    
    sleep(2);
    qDebug()<<"end ";
}

本线程的槽函数名称为ButtonReceive2,实现方式为:

void MainWindow::ButtonReceive2(int i)
{
    qDebug()<<"i am father, i got "<<i;
}

因此,Qt::QueuedConnection实现的效果应该是,子线程和主线程各自执行,互不打搅,但实际运行起来确是:
在这里插入图片描述
主线程的槽函数完全是在子线程结束后才执行的,为什么会这样呢?其实在老版的多线程写法中,QThread其实是管理线程的工具,它是属于主线程的,也是在主线程中调用,就像调用了QThread类中的一个方法,因此会按照槽的顺序去执行,所以Qt::QueuedConnection并没有生效。

新版多线程

当我们改用新版多线程子再去试一下:
主线程构造函数如下:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    m_threadRunInBack = new QThread(this);
    m_myThread = new MyThread();
    connect(this,&MainWindow::threadRun1,m_myThread,&MyThread::ButtonReceive2,Qt::QueuedConnection);
    connect(this,SIGNAL(threadRun1(int)),this,SLOT(ButtonReceive(int)),Qt::QueuedConnection);
    m_myThread->moveToThread(m_threadRunInBack);
}

signal函数如下

void MainWindow::on_pushButton_clicked()
{
    m_threadRunInBack->start();
    emit threadRun1(++i);
}

主线程槽函数如下:

void MainWindow::ButtonReceive(int i)
{
    qDebug()<<"i am father, i got "<<i;
}

子线程槽函数如下:

void MyThread::ButtonReceive2(int i){
    qDebug()<<"i am son , i got "<<i;
    qDebug()<<"sleeping...";
    sleep(2);
    qDebug()<<"end ";
}

再看下运行效果:
在这里插入图片描述
恰如预期。

进一步验证Qt::DirectConnection的效果

验证Qt::DirectConnection效果,Qt::DirectConnection是同步调用方式,及在信号发生者的线程去调用,在新版多线程写法中重复上述实验,因为槽的顺序是先子线程后主线程,因此打印顺序应该是先i am son 后 i am dad。
修改connect函数:

    connect(this,&MainWindow::threadRun1,m_myThread,&MyThread::ButtonReceive2,Qt::DirectConnection);
    connect(this,SIGNAL(threadRun1(int)),this,SLOT(ButtonReceive(int)));

运行看下结果:
在这里插入图片描述
正如所想,为什么跨线程要使用Qt::QueuedConnection的异步方式呢?个人理解为害怕子线程崩溃影响到主线程运行?或者子线程任务过于庞大,影响到主线成ui。
希望对大家有帮助!

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值