十、QThread多线程

为什么使用线程?

我们会遇到用户界面卡顿或者卡住的情况,比如某个程序员开发了一个按钮,他往按钮里面添加了很多代码,比如一些for循环,或者死循环,它没有使用到线程,当用户点击此按钮的时候,用户会发现界面已经卡死了。

新建一个QWidget项目,设置大小为(800, 480),添加一个按钮QPushButton,设置它的样式表:背景颜色为红色,无边框,悬停时背景颜色为蓝色。

我们来模仿下这个程序员往按钮里面添加很多代码,转到按钮的槽函数(clicked),

这就是为什么我们要使用线程。

线程与进程的区别

打开终端(Ctrl+shift+t),前提条件是先把项目的界面跑出来(ctrl+r),在终端上执行下面代码:

复制代码
ps -aux   //用来查看Ubuntu跑的进程都有哪些
ps -aux | grep 51    //找到用户界面的进程 我们的程序就是51
ps -mp 3290     //3290就是它进程的PID 就是把线程写在进程下面

好的,我们再来写一下进程与线程的关系,如果我们要在一个程序里面开辟多个进程的话,可以用QProcess,如果我们要在一个进程里面开辟多个线程的话,可以用QThread。

如何启动线程

我们这里以继承Qthread类来学习,继承QObject的线程我们私下自己学习(教程里面有原理都类似)。

接下来我们直接输出干货源代码:

复制代码
//widget.h
#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QThread>
#include <QDebug>

class MyThread;

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
    MyThread *myThread;
};

class MyThread : public QThread
{
    Q_OBJECT

public:
    MyThread(QWidget *parent = nullptr) {
        Q_UNUSED(parent)
    }
    ~MyThread() {

    }
    //只有这个run()方法在新的线程里面
    void run() override {
        qDebug() << "线程开启" << endl;
        while(1) {}
        qDebug() << "线程结束" << endl;
    }
};
#endif // WIDGET_H

//widget.cpp
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //一个应用程序至少要有一个进程,QProcess
    //一个进程至少要有一个线程,QThread
    myThread = new MyThread(this);

}

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


void Widget::on_pushButton_clicked()
{
    //system("sleep 5");//表示程序执行了5s
    //system("ping 192.168.1.1")//windos下大概是4s
    //启动线程
    myThread->start();
}

其它文件没有发生改变。这里我们执行下:

如何终止线程

我们复制一个QPushButton,改变这两个按钮的文本,原来的是开启线程,新建的是终止线程,并且将新建的这个转到槽(clicked),如下图:

如果我们再点击终止线程的话:

为了用户体验更好我们添加判断语句:

假设我们想开启多个线程怎么做呢?

那我们点击一次线程开启按钮之后,再次查看有几个线程,会发现多了一个线程是6个:

我们也可以这么查看:

假设我们再5s之内点击多个开启线程:

5s之后线程自动结束:

我们在帮助文档里面看到QThread有一个quit()方法,那终止线程时不使用它呢?

也就是说没有用到QEventLoop这个类,quit()是不会生效的。所以程序中我们用的是terminate()来终止线程的。

动态创建线程,使用指针的方式是会占内存的,每次点击按钮的时候都会开辟一个新的线程,这个线程运行结束之后并没有销毁。

在线程跑完之后我们要回收,怎么做?

相关推荐
小小晓.6 分钟前
C++ 值类别与完美转发深度剖析:从左值右值到 std::forward 源码解密
开发语言·c++·算法
小小龙学IT42 分钟前
Qt 元对象系统(Meta-Object System)深度解析:从 MOC 到反射式编程
数据库·qt
格林威1 小时前
C# 相机Burst模式图像采集:使用相机内存配合OpenCvSharp和Halcon实现短时间的高速采集的方法
开发语言·人工智能·数码相机·计算机视觉·c#·视觉检测·工业相机
子非鱼a1 小时前
【WEB】[NewStarCTF 公开赛赛道]UnserializeOne
前端·javascript·html
chen<>1 小时前
C++ 六种 memory_order:从原子性到线程间可见性.md
java·linux·开发语言·c++
一直C1 小时前
Linux系统编程|进程间通信IPC全套详解(1)(管道、信号)
linux·c语言·开发语言·网络·青少年编程·visual studio code
南雨北斗1 小时前
Vue3 v-model中的自动事件绑定
前端
会周易的程序员1 小时前
企业私有 AI 算力服务器架构设计:异构四节点 + QUIC 微服务
运维·服务器·c++·人工智能·微服务·架构
m0_734571761 小时前
深入理解C++ 类型转换<三>const_cast
开发语言·c++
luj_17681 小时前
合法避税与投资评估实战指南
c语言·开发语言·网络·经验分享·算法