Qt - 訊號與槽的第五個引數

[BORUTO]發表於2024-11-12

connent函式第五個引數的作用

connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)

第五個引數代表槽函式在哪個執行緒中執行 :

自動連線(Qt::AutoConnection),預設的連線方式,如果訊號與槽,也就是傳送者與接受者在同一執行緒,等同於直接連線;如果傳送者與接收者處在不同執行緒,等同於佇列連線

  • 在你的具體情況下,如果子執行緒發射訊號,並且該訊號的接收者是主執行緒中的一個物件,同時主執行緒執行著事件迴圈,那麼槽函式將在主執行緒中執行

直接連線(Qt::DirectConnection - 同步),當訊號發射時,槽函式立即直接呼叫。無論槽函式所屬物件在哪個執行緒,槽函式總在傳送者所線上程執行,即槽函式和訊號傳送者在同一執行緒

  • 如果訊號發射者和槽接收者位於不同的執行緒中,並且你使用了 Qt::DirectConnection,那麼就會違反 Qt 的執行緒安全規則,因為直接呼叫可能會在不同執行緒之間造成競爭條件或資料損壞。

佇列連線(Qt::QueuedConnection - 非同步),當Thread1觸發訊號後,訊號會在處理完前面的任務後再呼叫相應的槽函式,槽函式在接收者執行緒中執行,Thread1立即會執行下面任務,無需等待接收者執行緒執行槽函式完畢。

鎖定佇列連線(Qt::BlockingQueuedConnection - 阻塞):槽函式的呼叫時機與Qt::QueuedConnection一致,不過傳送完訊號後傳送者所線上程會阻塞,直到槽函式執行完。接收者和傳送者絕對不能在一個執行緒,否則程式會死鎖。在多執行緒間需要同步的場合可能需要這個。


自動連線(Qt::AutoConnection)

  • 自動連線(Qt::AutoConnection),預設的連線方式,如果訊號與槽,也就是傳送者與接受者在同一執行緒,等同於直接連線;如果傳送者與接收者處在不同執行緒,等同於佇列連線


直接連線(Qt::DirectConnection - 同步)

同執行緒

mainwindow.cpp(主執行緒)

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QThread>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(this,SIGNAL(sig()),this,SLOT(slot()),Qt::DirectConnection);

    emit sig();

    for(int i=0; i<10;i++)
    {
        qDebug() << i;
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::slot()
{
    qDebug()<<"執行槽函式";
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "thread1.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;    

private slots:
    void slot();
signals:
    void sig();
};

#endif // MAINWINDOW_H

結論:發射訊號後立馬執行槽函式。

Qt - 訊號與槽的第五個引數

不同執行緒

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    qDebug()<<u8"主執行緒ID"<<QThread::currentThreadId();

    connect(&m_thread1,SIGNAL(sigThread1()),this,SLOT(slot()),Qt::DirectConnection);

    m_thread1.start();
}
MainWindow::~MainWindow()
{
    delete ui;
}
void MainWindow::slot()
{
    qDebug()<<u8"執行槽函式---執行緒ID"<<QThread::currentThreadId();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <thread1.h>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    Thread1 m_thread1;

private slots:
    void slot();// 在主函式中定義需要呼叫的槽函式
};

#endif // MAINWINDOW_H

thread1.cpp

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

Thread1::Thread1(QThread *parent)
    : QThread(parent)
{

}

void Thread1::run()
{
    qDebug()<<u8"Thread1執行緒ID"<<QThread::currentThreadId();

    emit sigThread1();

    for(int i=0;i<10;i++)
    {
        qDebug()<<i;
    }
}

thread1.h

#ifndef THREAD1_H
#define THREAD1_H

#include <QThread>

class Thread1 : public QThread
{
    Q_OBJECT
public:
    explicit Thread1(QThread *parent = 0);

protected:
    virtual void run();

signals:
    void sigThread1();
};
#endif // THREAD1_H

結論:可以看出:emit發射訊號後立馬執行槽函式,沒有任何等待;並且槽函式執行在Thread1執行緒中;

Qt - 訊號與槽的第五個引數


佇列連線(Qt::QueuedConnection - 非同步)

同一執行緒

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QThread>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    connect(this,SIGNAL(sig()),this,SLOT(slot()),Qt::QueuedConnection);

    emit sig();

    for(int i=0; i<10;i++)
    {
        qDebug()<<i;
    }
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::slot()
{
    qDebug()<<u8"執行槽函式";
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "thread1.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

private slots:
    void slot();
signals:
    void sig();
};

#endif // MAINWINDOW_H

結論:可以看到:先執行完for迴圈(先把自己的事情處理完),當空閒後再執行槽函式。

Qt - 訊號與槽的第五個引數

不同執行緒

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qDebug()<<u8"主執行緒ID"<<QThread::currentThreadId();

    connect(&m_thread1,SIGNAL(sigThread1()),this,SLOT(slot()),Qt::QueuedConnection);

    m_thread1.start();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::slot()
{
    qDebug()<<u8"執行槽函式---執行緒ID"<<QThread::currentThreadId();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <thread1.h>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    Thread1 m_thread1;

private slots:
    void slot();

};
#endif // MAINWINDOW_H

thread1.cpp

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

Thread1::Thread1(QThread *parent)
    : QThread(parent)
{

}
void Thread1::run()
{
    qDebug()<<u8"Thread1執行緒ID"<<QThread::currentThreadId();

    emit sigThread1();

    for(int i=0;i<10000;i++) //此處為10000次,加長時間,以便更清楚的觀察現象
    {
        qDebug()<<i;
    }
}

thread1.h

#ifndef THREAD1_H
#define THREAD1_H

#include <QThread>

class Thread1 : public QThread
{
    Q_OBJECT
public:
    explicit Thread1(QThread *parent = 0);

protected:
    virtual void run();

signals:
    void sigThread1();
};

#endif // THREAD1_H

結論:

  • 可以看出:thread1執行緒傳送訊號後,thread1接著做自己的事,主執行緒同樣接著做自己的事。
  • 當主執行緒空閒時,再執行槽函式,槽函式執行在主執行緒中。

Qt - 訊號與槽的第五個引數

Qt - 訊號與槽的第五個引數


鎖定佇列連線(Qt::BlockingQueuedConnection - 阻塞)

  • 程式碼參考上面的,將Qt::QueuedConnection改為Qt::BlockingQueuedConnection即可。
  • 可以看到:規律同Qt::QueuedConnection,不過thread1執行緒傳送完訊號後,會阻塞,直到主執行緒的槽函式返回,thread1執行緒才會繼續向下執行。

Qt - 訊號與槽的第五個引數

相關文章