QT从入门到入土(五(1))——多线程(QThread)

本文详细介绍了Qt中使用QThread进行多线程编程的方法,包括QThread类的API、线程的创建与管理,以及如何通过派生QThread或使用信号槽实现多线程。强调了线程间的通信、资源管理和互斥锁的重要性,并通过实例展示了两种创建线程的方式及其区别。
摘要由CSDN通过智能技术生成

引言
前面几篇已经对C++的线程做了简单的总结,浅谈C++11中的多线程(三) - 唯有自己强大 - 博客园 (cnblogs.com)。本篇着重于Qt多线程的总结与实现。

跟C++11中很像的是,Qt中使用QThread来管理线程,一个QThread对象管理一个线程,在使用上有很多跟C++11中相似的地方,但更多的是Qt中独有的内容。另外,QThread对象也有消息循环exec()函数,即每个线程都有一个消息循环,用来处理自己这个线程的事件。

一,知识回顾
首先先来回顾一下一些知识点:

1,为什么需要多线程?

解决耗时操作堵塞整个程序的问题,一般我们会将耗时的操作放入子线程中

**2,进程和线程的区别:**

进程:一个独立的程序,拥有独立的虚拟地址空间,要和其他进程通信,需要使用进程通信的机制。

线程:没有自己的资源,都是共享进程的虚拟地址空间,多个线程通信存在隐患。

ps:在操作系统每一个进程都拥有独立的内存空间,线程的开销远小于进程,一个进程可以拥有多个线程。(因此我们常用多线程并发,而非多进程并发)

为了更容易理解多线程的作用,先看一个实例:

在主线程中运行一个10s耗时的操作。(通过按钮来触发)

#include "threadtest.h"
#include"qthread.h"
Threadtest::Threadtest(QWidget* parent)
    : QMainWindow(parent)
{
   
    ui.setupUi(this);
    connect(ui.btn_start, &QPushButton::clicked, this, &Threadtest::on_pushButton_clicked);

}
void Threadtest::on_pushButton_clicked()
{
   
    QThread::sleep(10);//主线程
}

可以看到程序运行过程中,整个线程都在响应10秒的耗时操作,对于线程的消息循环exec()函数就未响应了(就是你在这个过程中拖动界面是无反应的)
在这里插入图片描述

二,线程类 QThread
Qt 中提供了一个线程类,通过这个类就可以创建子线程了,Qt 中一共提供了两种创建子线程的方式,后边会依次介绍其使用方式。先来看一下这个类中提供的一些常用 API 函数:

2.1 常用共用成员函数

// QThread 类常用 API
// 构造函数
QThread::QThread(QObject *parent = Q_NULLPTR);
// 判断线程中的任务是不是处理完毕了
bool QThread::isFinished() const;
// 判断子线程是不是在执行任务
bool QThread::isRunning() const;

// Qt中的线程可以设置优先级
// 得到当前线程的优先级
Priority QThread::priority() const;
void QThread::setPriority(Priority priority);
优先级:
    QThread::IdlePriority        --> 最低的优先级
    QThread::LowestPriority
    QThread::LowPriority
    QThread::NormalPriority
    QThread::HighPriority
    QThread::HighestPriority
    QThread::TimeCriticalPriority
    QThread::InheritPriority    --> 最高的优先级, 默认是这个


// 退出线程, 停止底层的事件循环
// 退出线程的工作函数
void QThread::exit(int returnCode = 0);
// 调用线程退出函数之后, 线程不会马上退出因为当前任务有可能还没有完成, 调回用这个函数是
// 等待任务完成, 然后退出线程, 一般情况下会在 exit() 后边调用这个函数
bool QThread::wait(unsigned long time = ULONG_MAX);

2.2 信号槽

// 和调用 exit() 效果是一样的
// 代用这个函数之后, 再调用 wait() 函数
[slot] void QThread::quit();
// 启动子线程
[slot] void QThread::start(Priority priority = InheritPriority);
// 线程退出, 可能是会马上终止线程, 一般情况下不使用这个函数
[slot] void QThread::terminate();

// 线程中执行的任务完成了, 发出该信号
// 任务函数中的处理逻辑执行完毕了
[signal] void QThread::finished();
// 开始工作之前发出这个信号, 一般不使用
[signal] void QThread::started();

2.3静态函数

// 返回一个指向管理当前执行线程的QThread的指针
[static] QThread *QThread::currentThread();
// 返回可以在系统上运行的理想线程数 == 和当前电脑的 CPU 核心数相同
[static] int QThread::idealThreadCount();
// 线程休眠函数
[static] void QThread::msleep(unsigned long msecs);    // 单位: 毫秒
[static] void QThread::sleep(unsigned long secs);    // 单位: 秒
[static] void QThread::usleep(unsigned long usecs);    // 单位: 微秒

三,Qt中实现多线程的两种方法
🧡🧡3.1.派生QThread类对象的方法(重写Run函数)

首先,以文字形式来说明需要哪几个步骤。

自定义一个自己的类,使其继承自QThread类;
在自定义类中覆写QThread类中的虚函数run()。
这很可能就是C++中多态的使用。补充一点:QThread类继承自QObject类。

这里要重点说一下run()函数了。它作为线程的入口,也就是线程从run()开始执行,我们打算在线程中完成的工作都要写在run()函数中,个人认为可以把run()函数理解为线程函数。这也就是子类覆写基类的虚函数,基类QThread的run()函数只是简单启动exec()消息循环,关于这个exec()后面有很多东西要讲,请做好准备。
那么我们就来尝试用多线程实现10s耗时的操作:(用按钮触发)

1️⃣在编辑好ui界面后,先创建一个workThread的类。(继承自QThread类)
在这里插入图片描述

2️⃣在workThread1的类中重写run函数
在workThread.h的声明run函数:

#include <qthread.h>
class workThread : public QThread
{
   
public:
    void run();
};

在workThread.cpp中重写run函数(并打印子线程的ID):

#include "workThread.h"
#include"qdebug.h"
workThread::workThread(QObject* parent)
{
   

}
//重写run函数
void workThread::run()
{
   
    qDebug() << "当前子线程ID:" << QThread::currentThreadId();
    qDebug() << "开始执行线程";
    QThread::sleep(10);
    qDebug() << "线程结束";
}

3️⃣在主类中启动线程
threadtest.h中声明线程和按钮事件

#include <QtWidgets/QMainWindow>
#include "ui_threadtest.h"
#include"workThread.h"
#pragma execution_character_set("utf-8")
class Threadtest : public QMainWindow
{
   
    Q_OBJECT

public:
    Threadtest(QWidget *parent = Q_NULLPTR);

    
private:
    Ui::ThreadtestClass ui;
    void btn_clicked();
workThread* thread;
};

threadtest.cpp中实现,并启动子线程线程

#include "threadtest.h"
#include"qthread.h"
#include"qdebug.h"

Threadtest::Threadtest(QWidget* parent)
    : QMainWindow(parent)
{
   
    ui.setupUi(this);
    connect(ui.btn_start, &QPushButton::clicked, this, &Threadtest
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

We唯有自己强大

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值