欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Qt笔记-对connect中第5个进行多组实验(对信号与槽进一步认识)

程序员文章站 2022-06-09 11:35:34
...

官方关于第5个参数的介绍:

Qt::AutoConnection:默认的连接方式,当发起信号和接收槽到同一线程时这个值为Qt::DirectConnection,当在不同线程时这个值为Qt::QueuedConnection。

Qt::DirectConnection:发起信号槽函数会立马触发。这个槽函数会在发起信号的线程中执行。

Qt::QueuedConnection:将信号放到队列中,然后在槽函数线程依次执行。

Qt::BlockingQueuedConnection:在Qt::QueuedConnection的基础上,信号发起者当接收者的槽没有调用完成一直处于阻塞状态,这种容易形成死锁。

Qt::UniqueConnection:这个Type可以和上面所有的类型进行组合,使用"|"连接。当要变成其他方式时,QObject::connection会返回false。连接中这种方式static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection)。

 

代码结构如下:

Qt笔记-对connect中第5个进行多组实验(对信号与槽进一步认识)

其他源码如下:

Demo1.h

#ifndef DEMO1_H
#define DEMO1_H

#include <QThread>

class Demo1 : public QThread
{
    Q_OBJECT
    void run() override;

public:
    void setMsg(const QString &msg);

signals:
    void sendMsg(QString msg);

private:
    QString m_msg;
};

#endif // DEMO1_H

ReceClass.h

#ifndef RECECLASS_H
#define RECECLASS_H

#include <QObject>

class ReceClass : public QObject
{
    Q_OBJECT
public:
    explicit ReceClass(QObject *parent = nullptr);

public slots:
    void receMsg(QString msg);
};

#endif // RECECLASS_H

Demo1.cpp

#include "Demo1.h"
#include <QDebug>


void Demo1::run()
{
    for(int i = 0; i < 10; i++){

        emit sendMsg(this->m_msg);
        qDebug() << QThread::currentThread() << " emit " << this->m_msg << " over";
    }
    qDebug() << QThread::currentThread() << " msg:" << this->m_msg << " over";
}

void Demo1::setMsg(const QString &msg)
{
    this->m_msg = msg;
}

ReceClass.cpp

#include "ReceClass.h"
#include <QDebug>
#include <QThread>

ReceClass::ReceClass(QObject *parent) : QObject(parent)
{

}

void ReceClass::receMsg(QString msg)
{
    qDebug() << QThread::currentThread() << " Get msg: " +  msg;
    QThread::sleep(1);
}

下面来测试下接受者和发起者在不同线程使用Qt::QueuedConnection会造成什么样的现象

Qt笔记-对connect中第5个进行多组实验(对信号与槽进一步认识)

在发起者和接受者处于不同线程中,将数据会放到一个队列中,然后慢慢进行调用。这个功能很有用,信号与槽里面自带队列结构,在很多消息处理场景里面可以用这种模式。

 

如下Qt::QueueConnection时,现象如下:

Qt笔记-对connect中第5个进行多组实验(对信号与槽进一步认识)

这里可以看到,官方说这个一般是在发起者和接受者在同一线程时使用,当在不同线程时,接受者将会被放到发起者的线程里面进行调用,这个还是比较神奇的,Qt的信号与槽还是比较牛逼的。

代码如下:

#include <QCoreApplication>
#include "Demo1.h"
#include "ReceClass.h"
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //init
    ReceClass receClass;
    Demo1 demo1;
    Demo1 demo2;


    //bind
//    QObject::connect(&demo1, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, Qt::QueuedConnection);
//    QObject::connect(&demo2, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, Qt::QueuedConnection);

    QObject::connect(&demo1, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, Qt::DirectConnection);
    QObject::connect(&demo2, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, Qt::DirectConnection);


//    qDebug() << QObject::connect(&demo1, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection));
//    qDebug() << QObject::connect(&demo2, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection));
//    qDebug() << QObject::connect(&demo1, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, static_cast<Qt::ConnectionType>(Qt::DirectConnection | Qt::UniqueConnection));
//    qDebug() << QObject::connect(&demo2, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, static_cast<Qt::ConnectionType>(Qt::DirectConnection | Qt::UniqueConnection));

    //run
    demo1.setMsg("demo1");
    demo2.setMsg("demo2");


    demo1.start();
    demo2.start();


    return a.exec();
}

 

如下Qt::BlockingQueueConnection时,现象如下:

Qt笔记-对connect中第5个进行多组实验(对信号与槽进一步认识)

他是将数据放到队列里面,然后等槽函数触发完成后,再不阻塞,这里可以看到,发起者是一个线程,调用者是另外一个线程。

 

下面是关于Qt::UniqueConnection的使用,这个相当于辅助。

代码如下:

#include <QCoreApplication>
#include "Demo1.h"
#include "ReceClass.h"
#include <QDebug>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //init
    ReceClass receClass;
    Demo1 demo1;
    Demo1 demo2;


    //bind
//    QObject::connect(&demo1, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, Qt::QueuedConnection);
//    QObject::connect(&demo2, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, Qt::QueuedConnection);

//    QObject::connect(&demo1, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, Qt::DirectConnection);
//    QObject::connect(&demo2, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, Qt::DirectConnection);

    QObject::connect(&demo1, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, Qt::BlockingQueuedConnection);
    QObject::connect(&demo2, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, Qt::BlockingQueuedConnection);

    qDebug() << QObject::connect(&demo1, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection));
    qDebug() << QObject::connect(&demo2, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, static_cast<Qt::ConnectionType>(Qt::QueuedConnection | Qt::UniqueConnection));
    qDebug() << QObject::connect(&demo1, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, static_cast<Qt::ConnectionType>(Qt::DirectConnection | Qt::UniqueConnection));
    qDebug() << QObject::connect(&demo2, &Demo1::sendMsg, &receClass, &ReceClass::receMsg, static_cast<Qt::ConnectionType>(Qt::DirectConnection | Qt::UniqueConnection));

    //run
    demo1.setMsg("demo1");
    demo2.setMsg("demo2");


    demo1.start();
    demo2.start();


    return a.exec();
}

 

运行截图如下:

Qt笔记-对connect中第5个进行多组实验(对信号与槽进一步认识)

可见带上这个后,QObject::connection就会绑定失败。

本次实验就这么多。

 

 

源码打包下载地址:

https://github.com/fengfanchen/Qt/tree/master/ConnectionTest