当前位置: 首页 > article >正文

Qt开发-----线程调度

 目录

 前言

一、Linux下查看进程的情况

二、线程的创建

三、多线程的创建和使用


 前言

以下引用内容源自正点原子Qt开发指南文档。

        我们写的一个应用程序,应用程序跑起来后一般情况下只有一个线程,但是可能也有特殊情况。比如我们前面章节写的例程都跑起来后只有一个线程,就是程序的主线程。线程内的操作都是顺序执行的。恩,顺序执行?试着想一下,我们的程序顺序执行,假设我们的用户界面点击有某个操作是比较耗时的。您会发现界面点击完了,点击界面对应的操作还没有完成,所以就会冻结界面,不能响应,直到操作完成后,才返回到正常的界面里。如果我们的界面是这么设计的话,估计用户得发毛了。
        这种情况我们一般是创建一个单独的线程来执行这个比较耗时的操作。比如我们使用摄像头拍照保存照片。恩,很多朋友问,这个不算耗时吧。对的在电脑上使用 Qt 拍照,处理起来非常快。根本也不需要开启一个线程来做这种事。但是我们是否考虑在嵌入式的 CPU 上做这种事情呢?嵌入式的 CPU 大多数都没有电脑里的 CPU 主频(几 GHz)那么高,处理速度也不快。此时我们就需要考虑开多一个线程来拍照了。拍完照再与主线程(主线程即程序原来的线程)处理好照片的数据,就完成了一个多线程的应用程序了。
        官方文档里说,QThread 类提供了一种独立于平台的方法来管理线程。QThread 对象在程序中管理一个控制线程。QThreads 在 run()中开始执行。默认情况下,run()通过调用 exec()来启动事件循环,并在线程中运行 Qt 事件循环。您可以通过使用 QObject::moveToThread()将 worker对象移动到线程来使用它们。QThread 线程类是实现多线程的核心类。Qt 有两种多线程的方法,其中一种是继承 QThread的 run()函数,另外一种是把一个继承于 QObject 的类转移到一个 Thread 里。Qt4.8 之前都是使用继承 QThread 的 run()这种方法,但Qt4.8 之后,Qt 官方建议使用第二种方法。两种方法区别不大,用起来都比较方便,但继承 QObject 的方法更加灵活。所以 Qt 的帮助文档里给的参考是先给继承 QObject 的类,然后再给继承 QThread 的类。

一、Linux下查看进程的情况

  • 进程 (Process)

    • 进程是操作系统中资源分配的基本单位,代表一个正在执行的程序。每个进程都有自己的内存空间、系统资源(如文件描述符)和运行状态。
    • 一个进程可以包含一个或多个线程。
  • 线程 (Thread)

    • 线程是进程中执行的最小单位。一个线程是一个轻量级的执行单元,多个线程共享同一进程的内存空间和资源。
    • 线程之间的切换通常比进程切换更快,因为它们共享同一进程的上下文和资源,减少了上下文切换的开销。

总的来说,线程是CPU调度的最小单位,一个进程至少是有一个线程当然也可以有多个线程。这里打开你的命令行窗口( Ctrl+Alt+T),然后这里输入如下,查看当前系统的进程情况。

ps -aux

然后创建一个Qt项目,下面是这个按钮的槽函数,很显然当我们点击之后就会进到这个死循环里面去。

void Widget::on_pushButton_clicked()
{
    qDebug()<<"click"<<endl;
    while(1){

    }
    qDebug()<<"over"<<endl;
}

在你的Qtcreator去点击运行。

然后在命令行窗口输入:

ps -aux | grep QThread//QThread是Qt程序名字

 这条指令是查找名字为QThread的进程

这里就看到我这个进程的PID为8455,然后我要去查看这个进程下有哪些子进程。

ps -m 8455

ps -m 是 Linux 中用于显示当前进程及其线程的命令。具体来说,它显示了与指定进程相关的线程的信息。这条命令可以帮助你查看进程的线程状态和相关信息。 

这里就可以看到这个Qt程序带有另外的五个子线程,第一个是表示主线程,剩下几个是这个进程的分支也就是子线程。

然后回到你的QTcreator,点击这个按钮,然后就是卡死的情况了,这个程序就阻塞了。

好了现在就要处理这个东西了,这里就可以去用线程来去处理。

二、线程的创建

class MyThread : public QThread{
    Q_OBJECT
public:
    MyThread(QWidget* parent=nullptr){
        Q_UNUSED(parent);
    }

    ~MyThread(){
        qDebug()<<"die"<<endl;
    }
    void run() override{
        qDebug()<<"start "<<endl;
        while(1){

        }
        deleteLater();
    }
};
#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) //
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //sadasdw
    mythread= new MyThread(this);
}

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


void Widget::on_pushButton_clicked()
{
   mythread->start();
}

这里在Widget调用构造函数的时候就创建了这个线程,当我们去点击按钮的时候就是线程的开始。这里就可以实现不出现卡死,这就是线程的调度。

三、多线程的创建和使用

Widget.h代码:

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QThread>
#include <QtDebug>
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();
    void on_pushButton_2_clicked();

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


class MyThread : public QThread{
    Q_OBJECT
public:
    MyThread(QWidget* parent=nullptr){
        Q_UNUSED(parent);
    }

    ~MyThread(){
        qDebug()<<"die"<<endl;
    }
    void run() override{
        qDebug()<<"start "<<endl;
        msleep(5000);

        qDebug()<<"over "<<endl;
        deleteLater();
    }
};

#endif // WIDGET_H

这里我有一个MyThread线程的类,这个类重写了父类run()方法,当线程开启的时候这个就会调用这个方法。当run方法执行到最后一行的时候要用deleteLater()来去把这个线程的对象删除掉,否则堆区的内存就会无法释放。

下面是Widget.cpp文件

#include "widget.h"
#include "ui_widget.h"

Widget::Widget(QWidget *parent) //
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //sadasdw
    //mythread= new MyThread(this);
}

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


void Widget::on_pushButton_clicked()
{
  // mythread->start();
    MyThread *testThread = new MyThread(this);
    testThread->start();
}

这里就是点击一个按钮就会开启一个线程,每次点击之后都会去开启线程,这就是多线程的创建。

今日壁纸: 


http://www.kler.cn/news/362825.html

相关文章:

  • 【Flutter】页面布局:层叠布局(Stack、Positioned)
  • 基于STM32设计的养殖场环境监测系统(华为云IOT)
  • 算法五大排序(Java)
  • [LeetCode] 230. 二叉搜索树中第K小的元素
  • 数字后端实现静态时序分析STA Timing Signoff之min period violation
  • 记一次在一亿数据的大表里删除重复数据 by 勤勤学长
  • Python异常检测- 单类支持向量机(One-Class SVM)
  • Could not find artifact cn.hutool:hutool-all:jar:8.1 in central 导入Hutool报错
  • 鸿蒙HarmonyOS NEXT 5.0开发(2)—— ArkUI布局组件
  • 【推导过程】常用连续分布的数学期望、方差、特征函数
  • 031_基于nodejs的旅游推荐网站
  • Vue 的虚拟 DOM
  • 策略模式是一种行为设计模式
  • 基于neo4j知识图谱的菜谱推荐系统
  • OpenAI“草莓”大模型登场!先行者云科技一键体验
  • 驱动-----内核启动
  • C 语言入门教程
  • STM32(二十一):看门狗
  • VirtualBox虚拟机桥接模式固定ip详解
  • ARM/Linux嵌入式面经(五十):tp普联
  • HeterGCL 论文写作分析
  • C语言汇编概述
  • R语言机器学习算法实战系列(十)自适应提升分类算法 (Adaptive Boosting)
  • SCR相对标准偏差、氨氮比、截面速度,多平面计算
  • WIFI、NBIOT、4G模块调试AT指令连接华为云物联网服务器(MQTT协议)
  • 基于Java微信小程序的的儿童阅读系统的详细设计和实现(源码+lw+部署文档+讲解等)