zoukankan      html  css  js  c++  java
  • Qt跨线程的信号和槽的使用

    https://blog.csdn.net/libaineu2004/article/details/86487354

    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
    {
        Q_OBJECT
    Test()
    signals:
        void sigFirst();
    private slots:
        void slotFirst();
    }

    Test::Test(QWidget *parent)
    : QMainWindow(parent) {
        ui.setupUi(this);
        for (int i = 0; i < 5; i++) {//采用默认方式,连接5次
            connect(this, SIGNAL(sigFirst()), this, SLOT(slotFirst()));
        }

        emit sigFirst();
    }


    void Test::slotFirst() {
        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 {
        Q_OBJECT

    public:
        QtTestThread(QObject *parent);
        ~QtTestThread();
    protected:
        void run();
    signals:
        void sigSecond();
    };

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

    QtTestThread::QtTestThread(QObject *parent)
    : QThread(parent) {
    }

    QtTestThread::~QtTestThread() {
    }

    void QtTestThread::run() {
        emit sigSecond();
        qDebug() << QStringLiteral("信号发送完毕!");
    }

    调用线程类:

    class QtTestThread;
    class Test: public QMainWindow
    {
        Q_OBJECT
    Test()
    signals:
        void sigFirst();
    private slots:
        void slotThread();
    private:
        QtTestThread* testThread;
    }

    #include "QtTestThread.h"
    Test::Test(QWidget *parent)
    : QMainWindow(parent) {
        ui.setupUi(this);

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

        testThread->start();
    }

    void Test::slotThread() {
        qDebug() << QStringLiteral("线程发送的信号-槽函数执行!");
        QThread::sleep(3);
    }

    运行一下,输出内容:

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

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

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

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

    再次运行一下:

    "线程发送的信号-槽函数执行!"
    "信号发送完毕!"//时间等待3秒之后才输出这句话

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

     

    --

    完整的源码如下:

    头文件:

     1 #ifndef MAINWINDOW_H
     2 #define MAINWINDOW_H
     3  
     4 #include <QMainWindow>
     5 #include <QThread>
     6  
     7 namespace Ui {
     8 class MainWindow;
     9 }
    10  
    11 class QtTestThread : public QThread {
    12     Q_OBJECT
    13  
    14 public:
    15     QtTestThread(QObject *parent);
    16     ~QtTestThread();
    17  
    18 protected:
    19     void run();
    20  
    21 signals:
    22     void sigSecond();
    23 };
    24  
    25 class MainWindow : public QMainWindow
    26 {
    27     Q_OBJECT
    28  
    29 public:
    30     explicit MainWindow(QWidget *parent = nullptr);
    31     ~MainWindow();
    32  
    33 private:
    34     Ui::MainWindow *ui;
    35  
    36 signals:
    37     void sigFirst();
    38  
    39 private slots:
    40     void slotFirst();
    41     void slotThread();
    42  
    43 private:
    44     QtTestThread* testThread;
    45     int numCoon;
    46 };
    47  
    48 #endif // MAINWINDOW_H

    源文件:

     1 #include "mainwindow.h"
     2 #include "ui_mainwindow.h"
     3 #include <QDebug>
     4  
     5 QtTestThread::QtTestThread(QObject *parent)
     6     : QThread(parent)
     7 {
     8 }
     9  
    10 QtTestThread::~QtTestThread()
    11 {
    12 }
    13  
    14 void QtTestThread::run()
    15 {
    16     emit sigSecond();
    17     qDebug() << QStringLiteral("信号发送完毕!");
    18 }
    19  
    20 MainWindow::MainWindow(QWidget *parent) :
    21     QMainWindow(parent),
    22     ui(new Ui::MainWindow)
    23 {
    24     ui->setupUi(this);
    25  
    26     for (int i = 0; i < 5; i++) {//采用默认方式,连接5次
    27         //connect(this, SIGNAL(sigFirst()), this, SLOT(slotFirst()));//没有第五个参数,也就是采用默认的连接方式
    28         connect(this, SIGNAL(sigFirst()), this, SLOT(slotFirst()), Qt::UniqueConnection);//注意第五个参数
    29     }
    30  
    31     numCoon = 0;
    32     //emit sigFirst();
    33  
    34     testThread = new QtTestThread(this);
    35     //connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()));//没有第五个参数,也就是采用默认的连接方式
    36     //connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()), Qt::QueuedConnection);//效果同上
    37     connect(testThread, SIGNAL(sigSecond()), this, SLOT(slotThread()), Qt::BlockingQueuedConnection);//效果不同
    38     testThread->start();
    39 }
    40  
    41 MainWindow::~MainWindow()
    42 {
    43     delete ui;
    44 }
    45  
    46 void MainWindow::slotFirst()
    47 {
    48     numCoon++;
    49     qDebug() << QStringLiteral("信号第")<<numCoon<<QStringLiteral("次连接");
    50 }
    51  
    52 void MainWindow::slotThread()
    53 {
    54     qDebug() << QStringLiteral("线程发送的信号-槽函数执行!");
    55     QThread::sleep(3);
    56 }
  • 相关阅读:
    对象和数据绑定的问题
    Qt父窗口设置为桌面
    MIS的趋势必定是围绕机器取代人手,分工越来越细(小餐厅都支持微信自助点餐,结账时就打个折,相当于省了1、2个人手,SQL发明以后,程序员的工作更多了)
    使用开源软件做项目有风险
    开源免费的C/C++网络库(c/c++ sockets library)
    Bash
    sass
    Spire.XLS
    NET Core+Code First+Docker
    实战网络性能优化
  • 原文地址:https://www.cnblogs.com/Vancamel/p/11254117.html
Copyright © 2011-2022 走看看