QT 异步编程之多线程

一、概述

1、在进行桌面应用程序开发的时候,假设应用程序在某些情况下需要处理比较复制的逻辑,如果只有一个线程去处理,就会导致窗口卡顿,无法处理用户的相关操作 。这种情况下就需要使用多线程,其中一个线程处理窗口事件,其它线程进行逻辑运算,多个线程各司其职,不仅可以提高用户体验还可以提升程序的执行效率。

2、当前的主线程不能让它做非常复制的逻辑操作,如果你让它做了非常复杂的逻辑操作后,咱们再操作这个窗口的时候就会出现界面的卡顿,那么这些复杂的操作应该交给子线程去做。

3、默认的线程在Qt中称之为窗口线程,也叫主线程,负责窗口事件处理或者窗口控件数据的更新。

4、子线程复制后台的业务逻辑处理,子线程中不能对窗口对象做任何操作,这些事情需要交给窗口线程处理。

5、主线程和子线程之间如果要进行数据的传递,需要使用Qt中的信号与槽机制

二、多线程的使用方式一

1、需要创建一个线程的子类,让其继承QT中的线程类QThread

cpp 复制代码
class MyThread : public QThread
{
    ...............
}

2、重写父类的run方法,在该函数内部编写子线程要处理的具体的业务流程

cpp 复制代码
class MyThread : public QThread
{
    .........
protected:
    void run()
    {
        ........
    }
}

3、在主线程中创建子线程对象,new一个就可以了

cpp 复制代码
MyThread *subThread = new MyThread;

4、启动子线程,调用start()方法

cpp 复制代码
subThread->start();

5、示例 MyThread.h

cpp 复制代码
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
#include <QThread>

class MyThread : public QThread
{
    Q_OBJECT
public:
    MyThread();

    void print();

protected:
    void run() override;

signals:
};

#endif // MYTHREAD_H

6、 示例 MyThread.cpp

cpp 复制代码
#include "mythread.h"
#include <QDebug>

MyThread::MyThread()
{
}

void MyThread::print()
{
    qDebug() << "子线程成员函数的线程ID:" << QThread::currentThreadId();
}

void MyThread::run()
{
    qDebug() << "子线程的线程ID:" << QThread::currentThreadId();
}

7、main函数

cpp 复制代码
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MyThread w;
    w.start();

    qDebug() << "主线程ID:" << QThread::currentThreadId();

    w.print();

    return a.exec();
}

8、结果展示

9、结果分析:

(1)主线程和子线程的顺序不确定,偶尔主线程在前,偶尔子线程在前

(2)子线程类的成员函数包括槽函数是运行在主线程当中的,只有run()函数运行在子线程中

(3)如果run()函数中调用子线程的成员函数,那么该成员函数运行在子线程中

二、多线程的使用方式二

1、创建一个新的类,让这个类从QObject派生

cpp 复制代码
class MyWork : public QObject
{
    .........
}

2、在这个类中添加一个公共的成员函数,函数体就是我们要子线程中要执行的业务逻辑

cpp 复制代码
class MyWork : public QObject
{
public:
    ......
    //函数名自己指定,叫什么都可以
    void working();
}

3、在主线程中创建一个QThread对象,这就是子线程的对象

cpp 复制代码
QThread *sub = new QThread;

4、在主线程中创建工作的类对象(不要给创建的对象指定父对象)

cpp 复制代码
MyWork *work = new MyWork(this);  //error
MyWork *work = new MyWork;        //ok

5、将MyWork对象移动到创建的子线程对象中,需要调用QObject类提供的moveToThread()方法

cpp 复制代码
work->moveToThread(sub);

6、启动子线程,调用start(),这时候线程启动了,但是移动到线程中的对象并没有工作

7、调用MyWork类对象的工作函数,让这个函数开始执行,这时候是在移动到的那个子线程中运行的

8、示例 MyWork.h

cpp 复制代码
#ifndef MYWORK_H
#define MYWORK_H

#include <QObject>

class MyWork : public QObject
{
    Q_OBJECT
public:
    explicit MyWork(QObject *parent = nullptr);

    void print();

public slots:
    void doWork();

signals:
};

#endif // MYWORK_H

9、示例 MyWork.cpp

cpp 复制代码
#include "mywork.h"
#include <QDebug>
#include <QThread>

MyWork::MyWork(QObject *parent)
    : QObject{parent}
{
}

void MyWork::print()
{
    qDebug() << "成员函数ThreadID:" << QThread::currentThreadId();
}

void MyWork::doWork()
{
    qDebug() << "doWork ThreadId:" << QThread::currentThreadId();
}

10、示例 main

cpp 复制代码
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QThread *thread = new QThread();
    MyWork *worker = new MyWork;
    worker->moveToThread(thread);

    QObject::connect(thread, &QThread::started, worker, &MyWork::doWork);
    QObject::connect(thread, &QThread::started, worker, &MyWork::print);

    qDebug() << "主线程ID:" << QThread::currentThreadId();

    //启动线程
    thread->start();

    //调用成员函数
    worker->print();

    return a.exec();
}

11、运行结果

cpp 复制代码
22:38:21: Starting D:\QT\practice\mouseTrack\bin\debug\untitled.exe...
主线程ID: 0x56f0
成员函数ThreadID: 0x56f0
doWork ThreadId: 0x49d4
成员函数ThreadID: 0x49d4

12、结果分析

(1)通过信号与槽触发的成员函数、槽函数,执行都在新线程里面,通过对象调用执行,则在旧线程里面

三、两种方式的使用场景

1、QThread使用场景

(1)当需要创建一个独立的线程来执行某个任务,且需要对线程的整个生命周期进行管理时,适合使用 QThread 方式。

(2)当任务逻辑相对简单或独立,不需要频繁地进行线程间通信时,可以选择使用 QThread 方式。

2、moveToThread方式

(1)当需要将一个 QObject 对象移动到指定的线程中执行任务,或者需要多个对象在同一线程中协同工作时,适合使用 moveToThread() 方式。

(2)当需要灵活地控制对象和线程之间的关系,进行复杂的线程间通信时,可以选择使用 moveToThread() 方式。

相关推荐
hqxstudying2 小时前
Java异常处理
java·开发语言·安全·异常
wjs20245 小时前
状态模式(State Pattern)
开发语言
我命由我123455 小时前
Kotlin 数据容器 - List(List 概述、创建 List、List 核心特性、List 元素访问、List 遍历)
java·开发语言·jvm·windows·java-ee·kotlin·list
liulilittle5 小时前
C++ TAP(基于任务的异步编程模式)
服务器·开发语言·网络·c++·分布式·任务·tap
励志要当大牛的小白菜6 小时前
ART配对软件使用
开发语言·c++·qt·算法
武子康7 小时前
Java-80 深入浅出 RPC Dubbo 动态服务降级:从雪崩防护到配置中心秒级生效
java·分布式·后端·spring·微服务·rpc·dubbo
爱装代码的小瓶子8 小时前
数据结构之队列(C语言)
c语言·开发语言·数据结构
YuTaoShao9 小时前
【LeetCode 热题 100】131. 分割回文串——回溯
java·算法·leetcode·深度优先
源码_V_saaskw10 小时前
JAVA图文短视频交友+自营商城系统源码支持小程序+Android+IOS+H5
java·微信小程序·小程序·uni-app·音视频·交友
Maybe_ch10 小时前
.NET-键控服务依赖注入
开发语言·c#·.net