qt 槽函数在那个线程执行由什么决定

1.概要

在Qt中,槽函数在哪个线程中执行,主要由以下几个方面决定:

1. 信号和槽的连接类型

Qt中的信号和槽可以通过QObject::connect函数进行连接,QObject::connect函数有一个参数用于指定连接类型,这个连接类型决定了槽函数在哪个线程中执行。主要的连接类型有以下几种:

  • Qt::DirectConnection:槽函数在信号发出者所在的线程中执行。这种连接类型是同步的,槽函数会立即被调用。
  • Qt::QueuedConnection:槽函数在信号接收者所在的线程中执行。信号发出者将信号和参数打包为事件,并将其添加到接收者线程的事件队列中。接收者线程的事件循环在适当的时候处理事件队列,从而执行槽函数。这种连接类型是异步的,槽函数不会立即被调用。
  • Qt::AutoConnection:这是默认的连接类型。如果信号和槽在同一个线程中,则等同于Qt::DirectConnection;如果信号和槽在不同的线程中,则等同于Qt::QueuedConnection。

2. 接收者对象的线程归属

槽函数在哪个线程中执行,还取决于接收者对象(即槽函数所属的对象)所在的线程。如果接收者对象所在的线程与信号发出者所在的线程不同,且连接类型为Qt::QueuedConnection或Qt::AutoConnection(在跨线程情况下),则槽函数会在接收者对象所在的线程中执行。

3. 线程的事件循环

对于Qt::QueuedConnection类型的连接,接收者线程的事件循环是必须的。如果接收者线程没有事件循环,那么即使信号被发出,槽函数也不会被调用。因此,在使用Qt::QueuedConnection时,需要确保接收者线程已经启动了事件循环。

4. 手动控制线程归属

在Qt中,可以通过QObject::moveToThread函数将对象移动到另一个线程中。这样,对象的槽函数就会在该线程中执行。这种方法允许开发者更灵活地控制槽函数的执行线程。

综上所述,Qt中槽函数在哪个线程中执行,主要由信号和槽的连接类型、接收者对象的线程归属、线程的事件循环以及手动控制线程归属等因素决定。在实际开发中,需要根据具体的需求和场景来选择合适的连接类型和线程管理方式。

2.实验 

1.实验1 槽函数不同线程在槽函数的线程运行,相同在发信号的函数运行,(本质就是在槽函数所在的线程运行)

1.代码

工程文件cmake
cmake_minimum_required(VERSION 3.14)

project(untitled8 LANGUAGES CXX)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)

add_executable(untitled8
  main.cpp
  WorkerA.h
)
target_link_libraries(untitled8 Qt${QT_VERSION_MAJOR}::Core)

include(GNUInstallDirs)
install(TARGETS untitled8
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)
2.线程文件 
#ifndef WORKERA_H
#define WORKERA_H
#include <QThread>
#include <QObject>
#include <QDebug>

class WorkerA : public QObject {
    Q_OBJECT
public slots:
    void doWork() {
        // 在这里做一些工作,然后发出信号
        qDebug() << "WorkerA: Doing work in thread" << QThread::currentThread();
        emit signalFromA();
        // 输出当前主线程的ID
        qDebug() << "WorkerA::doWork thread ID:" << QThread::currentThreadId();
    }

signals:
    void signalFromA();
};

class WorkerB : public QObject {
    Q_OBJECT
public slots:
    void handleSignalFromA() {
        qDebug() << "WorkerB: Received signal in thread" << QThread::currentThread();
        // 输出当前主线程的ID
        qDebug() << "WorkerB::handleSignalFromA thread ID:" << QThread::currentThreadId();
        // 在这里处理信号
    }
};

#endif // WORKERA_H
3.主函数 
#include <QCoreApplication>
#include <QThread>
#include <QObject>
#include <QDebug>

#include "WorkerA.h"

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

    // 输出当前主线程的ID
    qDebug() << "Main thread ID:" << QThread::currentThreadId();

    // 创建 WorkerA 和 WorkerB 对象
    WorkerA workerA;
    WorkerB workerB;

    // 创建线程对象
    QThread threadA;
    QThread threadB;

    // 将 WorkerA 移动到 threadA,将 WorkerB 移动到 threadB
    workerA.moveToThread(&threadA);
    workerB.moveToThread(&threadB);

    // 连接信号和槽
    QObject::connect(&workerA, &WorkerA::signalFromA, &workerB, &WorkerB::handleSignalFromA);

    // 连接 threadA 的 started 信号到 workerA 的 doWork 槽
    QObject::connect(&threadA, &QThread::started, &workerA, &WorkerA::doWork);

    // 启动线程
    threadA.start();
    threadB.start();

    // 等待线程完成(可选,这将使主线程等待子线程结束)
    threadA.wait();
    threadB.wait();

    return app.exec();
}

2.运行结果

Main thread ID: 0x71f0
WorkerA: Doing work in thread QThread(0xd1a0dff680)
WorkerA::doWork thread ID: 0x34bc
WorkerB: Received signal in thread QThread(0xd1a0dff670)
WorkerB::handleSignalFromA thread ID: 0x6e54

2.实验2 槽函在自己的线程运行

1.变更点

变更前

// 连接信号和槽
    QObject::connect(&workerA, &WorkerA::signalFromA, &workerB, &WorkerB::handleSignalFromA);

变更后 

添加 Qt::QueuedConnection

// 连接信号和槽
    QObject::connect(&workerA, &WorkerA::signalFromA, &workerB, &WorkerB::handleSignalFromA,Qt::QueuedConnection);

2.运行结果

Main thread ID: 0x56fc
WorkerA: Doing work in thread QThread(0xcc74dffaf0)
WorkerA::doWork thread ID: 0x2860
WorkerB: Received signal in thread QThread(0xcc74dffae0)
WorkerB::handleSignalFromA thread ID: 0x4608 

可以看到线程id不同和实验1的效果完全相同 

从结果来看和“实验1”一样 

3.实验三 槽函数在发信号的线程执行

1.变更点

变更前

// 连接信号和槽
    QObject::connect(&workerA, &WorkerA::signalFromA, &workerB, &WorkerB::handleSignalFromA);

变更后

// 连接信号和槽
    QObject::connect(&workerA, &WorkerA::signalFromA, &workerB, &WorkerB::handleSignalFromA,Qt::DirectConnection);

 2.运行结果

Main thread ID: 0x6d00
WorkerA: Doing work in thread QThread(0x39dd7ff800)
WorkerB: Received signal in thread QThread(0x39dd7ff800)
WorkerB::handleSignalFromA thread ID: 0x6164
WorkerA::doWork thread ID: 0x6164 

可以看到线程id相同 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值