Qt跨线程的信号和槽的使用

简介: Qt跨线程的信号和槽的使用

connect用于连接qt的信号和槽,在qt编程过程中不可或缺。它其实有第五个参数,只是一般使用默认值,在满足某些特殊需求的时候可能需要手动设置。


Qt::AutoConnection: 默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。


Qt::DirectConnection:槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成奔溃。


Qt::QueuedConnection:槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。


Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。


Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接。


QObject::connect()本身是线程安全的。槽函数一般是不安全的。


1.信号和槽函数在同一个线程中的情况

class Test: public QMainWindow

{undefined

   Q_OBJECT

Test()

signals:

   void sigFirst();

private slots:

   void slotFirst();

}


Test::Test(QWidget *parent)

: QMainWindow(parent) {undefined

   ui.setupUi(this);

   for (int i = 0; i < 5; i++) {//采用默认方式,连接5次

       connect(this, SIGNAL(sigFirst()), this, SLOT(slotFirst()));

   }


   emit sigFirst();

}



void Test::slotFirst() {undefined

   numCoon++;

   qDebug() << QStringLiteral("信号第")<<numCoon<<QStringLiteral("次连接");

}


运行之后的输出内容:


"信号第" 1 "次连接"

"信号第" 2 "次连接"

"信号第" 3 "次连接"

"信号第" 4 "次连接"

"信号第" 5 "次连接"`


如果代码修改一下,改为:


connect(this, SIGNAL(sigFirst()), this, SLOT(slotFirst()), Qt::UniqueConnection);//注意第五个参数


再次运行一下,查看输出:


"信号第" 1 "次连接"


这次只发送了一次信号,但是咱们连接了5次,所以采用Qt::UniqueConnection方式连接,无论连接多少次,只发送一次信号,也只会执行一次槽函数


2.信号和槽函数在不同线程中的情况

自定义线程类:


#pragma once


#include <QThread>


class QtTestThread : public QThread {undefined

   Q_OBJECT


public:

   QtTestThread(QObject *parent);

   ~QtTestThread();

protected:

   void run();

signals:

   void sigSecond();

};


#include "QtTestThread.h"

#include <QDebug>


QtTestThread::QtTestThread(QObject *parent)

: QThread(parent) {undefined

}


QtTestThread::~QtTestThread() {undefined

}


void QtTestThread::run() {undefined

   emit sigSecond();

   qDebug() << QStringLiteral("信号发送完毕!");

}


调用线程类:


class QtTestThread;

class Test: public QMainWindow

{undefined

   Q_OBJECT

Test()

signals:

   void sigFirst();

private slots:

   void slotThread();

private:

   QtTestThread* testThread;

}


#include "QtTestThread.h"

Test::Test(QWidget *parent)

: QMainWindow(parent) {undefined

   ui.setupUi(this);


   testThread = new QtTestThread(this);

   connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()));//没有第五个参数,也就是采用默认的连接方式


   testThread->start();

}


void Test::slotThread() {undefined

   qDebug() << QStringLiteral("线程发送的信号-槽函数执行!");

   QThread::sleep(3);

}


运行一下,输出内容:


"信号发送完毕!"

"线程发送的信号-槽函数执行!"


由此可以看出,信号发送完成信号后,就直接运行下面的代码了,而发送的信号就会被放到主线程的信号队列中等待执行。


咱们信号槽的连接方式修改一下,添加信号槽的连接方式 Qt::BlockingQueuedConnection:


connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()), Qt::BlockingQueuedConnection);


再次运行一下:


"线程发送的信号-槽函数执行!"

"信号发送完毕!"//时间等待3秒之后才输出这句话


采用Qt::BlockingQueuedConnection的连接方式就实现了信号和槽函数的同步执行。



--


完整的源码如下:


头文件:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QThread>
namespace Ui {
class MainWindow;
}
class QtTestThread : public QThread {
    Q_OBJECT
public:
    QtTestThread(QObject *parent);
    ~QtTestThread();
protected:
    void run();
signals:
    void sigSecond();
};
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
private:
    Ui::MainWindow *ui;
signals:
    void sigFirst();
private slots:
    void slotFirst();
    void slotThread();
private:
    QtTestThread* testThread;
    int numCoon;
};
#endif // MAINWINDOW_H



源文件:


#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
QtTestThread::QtTestThread(QObject *parent)
    : QThread(parent)
{
}
QtTestThread::~QtTestThread()
{
}
void QtTestThread::run()
{
    emit sigSecond();
    qDebug() << QStringLiteral("信号发送完毕!");
}
MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    for (int i = 0; i < 5; i++) {//采用默认方式,连接5次
        //connect(this, SIGNAL(sigFirst()), this, SLOT(slotFirst()));//没有第五个参数,也就是采用默认的连接方式
        connect(this, SIGNAL(sigFirst()), this, SLOT(slotFirst()), Qt::UniqueConnection);//注意第五个参数
    }
    numCoon = 0;
    //emit sigFirst();
    testThread = new QtTestThread(this);
    //connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()));//没有第五个参数,也就是采用默认的连接方式
    //connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()), Qt::QueuedConnection);//效果同上
    connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()), Qt::BlockingQueuedConnection);//效果不同
    testThread->start();
}
MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::slotFirst()
{
    numCoon++;
    qDebug() << QStringLiteral("信号第")<<numCoon<<QStringLiteral("次连接");
}
void MainWindow::slotThread()
{
    qDebug() << QStringLiteral("线程发送的信号-槽函数执行!");
    QThread::sleep(3);
}


相关文章
|
11月前
|
编译器
(9)Qt中信号与槽重载的解决方案
本文介绍了在Qt中处理信号与槽重载问题的三种解决方案:使用函数指针、Qt提供的QOverload类和Qt4的宏方式。
471 3
|
11月前
(8)Qt中的自定义信号
本文介绍了如何在Qt框架中创建和使用自定义信号,并通过一个父子窗口切换的示例来展示自定义信号的实现和应用。
326 3
(8)Qt中的自定义信号
|
7月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
通过本文,您可以了解如何在业务线程中注册和处理Linux信号。正确处理信号可以提高程序的健壮性和稳定性。希望这些内容能帮助您更好地理解和应用Linux信号处理机制。
118 26
|
7月前
|
Linux
Linux编程: 在业务线程中注册和处理Linux信号
本文详细介绍了如何在Linux中通过在业务线程中注册和处理信号。我们讨论了信号的基本概念,并通过完整的代码示例展示了在业务线程中注册和处理信号的方法。通过正确地使用信号处理机制,可以提高程序的健壮性和响应能力。希望本文能帮助您更好地理解和应用Linux信号处理,提高开发效率和代码质量。
126 17
|
安全 C++ Windows
Qt信号与槽机制
Qt信号与槽机制
173 1
|
9月前
|
传感器 安全
第四问:QT中信号和槽原理
Qt的信号与槽机制是观察者模式的典型实现,允许对象间通信而不直接依赖。信号用于通知事件发生,槽是响应信号的函数,通过`QObject::connect()`连接。这种机制实现了松耦合、灵活扩展和自动通知,适用于UI更新和数据绑定等场景。
237 1
|
10月前
|
C++
003 Qt_信号和槽-上
本文介绍了Qt中的信号与槽机制,包括信号和槽的概念、本质及连接方法,并演示了如何自定义槽函数。信号是事件的体现,槽是对信号的响应函数。通过信号与槽,可以将独立的控件关联起来,实现复杂的交互逻辑。文中还详细展示了如何在Qt项目中定义和使用槽函数,通过实例代码和图形化界面操作,帮助读者更好地理解和应用这一机制。
195 1
003 Qt_信号和槽-上
|
12月前
|
网络协议 安全
QT多线程
本文详细介绍了在Qt中如何正确使用QThread以及信号槽跨线程的使用方式,包括线程的正确退出方法和QObject在不同线程中创建子对象时可能遇到的问题。同时,文章还提供了相关博客和资料的链接,用于进一步学习和参考。
252 3
|
12月前
|
数据库 数据库管理
qt对sqlite数据库多线程的操作
本文总结了在Qt中进行SQLite数据库多线程操作时应注意的四个关键问题,包括数据库驱动加载、加锁、数据库的打开与关闭,以及QsqlQuery变量的使用。
680 1
|
12月前
自己动手写QT多线程demo
本文是作者关于如何编写Qt多线程demo的教程,介绍了如何实现多线程功能,包括可暂停和继续的功能。文章提供了部分示例代码,展示了如何创建线程类、启动和管理线程,以及线程间的通信。同时,还提供了相关参考资料和免费下载链接。
245 0

推荐镜像

更多
  • qt