Qt的信号槽连接机制如下:
- Qt::AutoConnection:默认,如果信号和槽在同一线程,使用DirectConnection;否则使用QueuedConnection。
- Qt::DirectConnection:槽函数立即在信号发出的线程执行,同步。
- Qt::QueuedConnection:槽函数在接收者的线程的事件循环中异步执行。
- Qt::BlockingQueuedConnection:类似Queued,但发送线程会阻塞直到槽执行完毕,不能在同一个线程中使用,否则死锁。
- Qt::UniqueConnection:和Auto相同,但确保连接唯一。
- Qt::SingleShotConnection:槽只触发一次,之后自动断开。
代码
worker.h
#ifndef WORKER_H
#define WORKER_H
#include <QObject>
class Worker : public QObject {
Q_OBJECT
public:
explicit Worker(QObject* parent = nullptr);
public slots:
void doWork();
signals:
void resultReady(const QString& string);
};
#endif // WORKER_H
worker.cpp
#include "worker.h"
#include <QDateTime>
#include <QDebug>
#include <QThread>
Worker::Worker(QObject* parent) : QObject{parent} { qDebug() << "worker" << this << this->thread(); }
void Worker::doWork() {
qDebug() << "do work" << this << this->thread();
QThread::sleep(3);
QString result = "Task completed at" + QDateTime::currentDateTime().toString();
qDebug() << result;
emit resultReady(result);
}
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "worker.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow {
Q_OBJECT
public:
MainWindow(QWidget* parent = nullptr);
~MainWindow();
void disconnect();
private slots:
void on_pushButton_2_clicked();
void on_stst_clicked();
void on_stdt_clicked();
void on_pushButton_3_clicked();
void on_pushButton_clicked();
void on_pushButton_4_clicked();
void on_pushButton_5_clicked();
void on_pushButton_6_clicked();
signals:
void sameThreadSend();
void diffThreadSend();
private:
Ui::MainWindow* ui;
QThread* m_workThread;
Worker* m_workerSameThread;
Worker* m_workerDiffThread;
};
#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include <QThread>
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget* parent) : QMainWindow(parent), ui(new Ui::MainWindow) {
ui->setupUi(this);
qDebug() << "MainWindow" << this << this->thread();
m_workThread = new QThread(this);
m_workerSameThread = new Worker(this);
m_workerDiffThread = new Worker();
m_workerDiffThread->moveToThread(m_workThread);
m_workThread->start();
}
MainWindow::~MainWindow() {
delete ui;
m_workThread->exit();
m_workThread->deleteLater();
}
void MainWindow::on_stst_clicked() {
qDebug() << "同线程" << this->thread();
qDebug() << "before";
emit this->sameThreadSend();
qDebug() << "after";
}
void MainWindow::on_stdt_clicked() {
qDebug() << "不同线程" << this->thread();
qDebug() << "before";
emit this->diffThreadSend();
qDebug() << "after";
}
void MainWindow::disconnect() {
qDebug() << "断开连接";
QObject::disconnect(this, &MainWindow::sameThreadSend, m_workerSameThread, &Worker::doWork);
QObject::disconnect(this, &MainWindow::diffThreadSend, m_workerDiffThread, &Worker::doWork);
}
void MainWindow::on_pushButton_clicked() {
disconnect();
qDebug() << "自动连";
connect(this, &MainWindow::sameThreadSend, m_workerSameThread, &Worker::doWork, Qt::AutoConnection);
connect(this, &MainWindow::diffThreadSend, m_workerDiffThread, &Worker::doWork, Qt::AutoConnection);
}
void MainWindow::on_pushButton_2_clicked() {
disconnect();
qDebug() << "直连";
connect(this, &MainWindow::sameThreadSend, m_workerSameThread, &Worker::doWork, Qt::DirectConnection);
connect(this, &MainWindow::diffThreadSend, m_workerDiffThread, &Worker::doWork, Qt::DirectConnection);
}
void MainWindow::on_pushButton_3_clicked() {
disconnect();
qDebug() << "queue连";
connect(this, &MainWindow::sameThreadSend, m_workerSameThread, &Worker::doWork, Qt::QueuedConnection);
connect(this, &MainWindow::diffThreadSend, m_workerDiffThread, &Worker::doWork, Qt::QueuedConnection);
}
void MainWindow::on_pushButton_4_clicked() {
disconnect();
qDebug() << "阻塞连";
connect(this, &MainWindow::sameThreadSend, m_workerSameThread, &Worker::doWork, Qt::BlockingQueuedConnection);
connect(this, &MainWindow::diffThreadSend, m_workerDiffThread, &Worker::doWork, Qt::BlockingQueuedConnection);
}
void MainWindow::on_pushButton_5_clicked() {
disconnect();
qDebug() << "unique连";
connect(this, &MainWindow::sameThreadSend, m_workerSameThread, &Worker::doWork, Qt::UniqueConnection);
connect(this, &MainWindow::diffThreadSend, m_workerDiffThread, &Worker::doWork, Qt::UniqueConnection);
}
void MainWindow::on_pushButton_6_clicked()
{
disconnect();
qDebug() << "singleshot连";
connect(this, &MainWindow::sameThreadSend, m_workerSameThread, &Worker::doWork, Qt::SingleShotConnection);
connect(this, &MainWindow::diffThreadSend, m_workerDiffThread, &Worker::doWork, Qt::SingleShotConnection);
}
main.cpp
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.ui
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="stst">
<property name="geometry">
<rect>
<x>20</x>
<y>50</y>
<width>141</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>Start Task SameThread</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_2">
<property name="geometry">
<rect>
<x>100</x>
<y>10</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>直连</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_3">
<property name="geometry">
<rect>
<x>180</x>
<y>10</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>queue连</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_4">
<property name="geometry">
<rect>
<x>260</x>
<y>10</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>阻塞连</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_5">
<property name="geometry">
<rect>
<x>350</x>
<y>10</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Unique连</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton_6">
<property name="geometry">
<rect>
<x>430</x>
<y>10</y>
<width>101</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>SingleShot连</string>
</property>
</widget>
<widget class="QPushButton" name="stdt">
<property name="geometry">
<rect>
<x>20</x>
<y>90</y>
<width>141</width>
<height>31</height>
</rect>
</property>
<property name="text">
<string>Start Task DiffThread</string>
</property>
</widget>
<widget class="QPushButton" name="pushButton">
<property name="geometry">
<rect>
<x>20</x>
<y>10</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>自动连</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>
结果分析
连接方式 | 同线程行为 | 跨线程行为 | 原因解析 |
---|---|---|---|
自动 | 同步阻塞 | 异步非阻塞 | 自动选择直接/队列连接 |
直接 | 同步阻塞 | 同步阻塞(槽函数在主线程执行) | 直接调用槽函数,跨线程时忽略线程边界 |
队列 | 同步执行(事件队列优化) | 异步非阻塞 | 同线程队列连接优化为直接调用,跨线程通过事件队列异步处理 |
阻塞队列 | 死锁 | 同步阻塞 | 主线程等待子线程完成,但槽函数在子线程执行 |
唯一 | 同步阻塞 | 异步非阻塞 | 唯一连接不改变执行逻辑 |
单次 | 同步阻塞 | 异步非阻塞 | 连接自动断开,首次行为同自动连接 |
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。