Qt中的线程详解

2023-11-07

概述
在多核时代,CPU 的主频已经进入瓶 颈,另辟蹊径地提高程序运行效率就是使用线程,充分利用多核的优势。线程可以看做是“轻量级进程”,线程即可以由操作系统管理,也可以由应用程序管

1.为什么要使用线程:

我们都知道,进程线程的概念是非常重要的,也可以看看Linux下的线程,一般是在多任务的时候需要用到线程进程,说简单一点处理多核可以跑多个while(1)之外,进程线程也可以跑多个while(1)
我们使用一个定时器和LCD显示定时器的计数.
比如以下示例:

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    /*定时器的创建*/
    MyTimer = new QTimer(this);

    /*定时器启动自动触发timeout信号*/
    connect(MyTimer, &QTimer::timeout, this, &Widget::dealtimer);
}

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

void Widget::dealtimer()
{
    static int i = 0;
    i++;
    /*设置LCD*/
    ui->lcdNumber->display(i);

}

/*当界面有过于复杂的数据处理的时候需要用到多线程
避免界面卡死*/
void Widget::on_Lcd_Start_clicked()
{
    /*如果定时器没有工作*/
    if(MyTimer->isActive() == false)
    {
        MyTimer->start(1000);
    }
    /*非常复杂的数据处理 耗时较长*/
    QThread::sleep(5);

    /*处理完数据关闭定时器*/
    //MyTimer->stop();
}

注:使用QThread中的sleep函数,让程序等待5s,我们现在目前只有一个主线程,所以在点击按钮之后会造成定时器虽然设置了,但是LCD的显示数字是不会该变得,因为sleep了5s所以说需要等5s之后才会开始变化,也就是说如果sleep换成一个数据处理的函数时候,在数据处理函数执行的这段时间,其余的程序无法运行,会造成窗口卡住,无响应等问题。所以我们使用多线程来解决执行复杂数据处理函数时不去影响都别的程序运行。

2.线程的创建使用方法一:

2.1线程创建的步骤:

  1. 自定义一个类,继承于QThread,并且只有一个线程处理函数(和主线程不再同一个线程),这个线程处理函数就是重写父类中的run函数。
  2. 线程处理函数里面写入需要执行的复杂数据处理
  3. 启动线程不能直接调用run函数,需要使用对象来调用start函数实现线程启动
  4. 线程处理函数执行结束后可以定义一个信号来告诉主线程
  5. 最后关闭线程
    2.2将上述程序进行修改
/*******************mythread.h**************************/
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
/*自定义一个类重写线程处理函数*/
class Mythread : public QThread
{
    Q_OBJECT
public:
    explicit Mythread(QObject *parent = nullptr);
/*线程处理函数,不能直接调用,通过start简介调用*/
protected:
/*线程处理函数*/
    void run();

signals:
/*自定义一个线程处理函数指向完成后的一个信号*/
    void runDone();

};

#endif // MYTHREAD_H
/*******************mythread.cpp**************************/
#include "mythread.h"

Mythread::Mythread(QObject *parent) : QThread(parent)
{

}

void Mythread::run()
{
    /*很复杂的数据处理*/
    sleep(5);
    /*执行结束后发送信号*/
    emit runDone();
}

/*******************widget.cpp****************************/
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    /*定时器的创建*/
    MyTimer = new QTimer(this);
    /*定义自定义线程类对象*/
    thread = new Mythread(this);

    /*定时器启动自动触发timeout信号*/
    connect(MyTimer, &QTimer::timeout, this, &Widget::dealtimer);
    /*connect自定义线程类中的信号 可以知道线程处理函数执行完成*/
    connect(thread, &Mythread::runDone, this, &Widget::dealthread);
    /*关闭窗口时触发以下信号 关闭窗口后关闭线程*/
    connect(this, &Widget::destroyed, this, &Widget::stopthread);
}

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

void Widget::dealtimer()
{
    static int i = 0;
    i++;
    /*设置LCD*/
    ui->lcdNumber->display(i);

}

/*当界面有过于复杂的数据处理的时候需要用到多线程
避免界面卡死*/
void Widget::on_Lcd_Start_clicked()
{
    /*如果定时器没有工作*/
    if(MyTimer->isActive() == false)
    {
        MyTimer->start(100);
    }
    /*非常复杂的数据处理 耗时较长*/
    //QThread::sleep(5);
    thread->start();

    /*处理完数据关闭定时器*/
    //MyTimer->stop();
}
/*线程处理函数指向完成后发送的信号处理*/
void Widget::dealthread()
{
	/*关闭定时器*/
    MyTimer->stop();
    qDebug() << "处理完毕";
}

void Widget::stopthread()
{

    thread->quit();
    /*等待线程处理完事情之后*/
    thread->wait();
}

执行效果如下:
在这里插入图片描述

至于为上面是在45的时候停止的,由于中间过程启动时间导致的。
对于关闭线程时候使用的两种方法:


void terminate()
/*此函数直接关闭线程不等待线程任务结束*/
void quit()
/*此函数等待线程任务结束之后关闭线程*/

3.线程的创建使用方法二:

3.1线程创建的步骤:

  1. 自定义一个类,只需要继承QObject即可,并且线程处理函数名字随便取,但是也只有一个线程处理函数
  2. 创建一个自定义线程类的对象,不能指定父对象
  3. 创建一个QThread类的对象,可以指定父对象
  4. 将自定义线程对象加入到QThread类的对象,使用
  5. 启动线程的时候要注意:启动QThread类的对象线程,调用start函数只是启动了线程,但是没有开启线程处理函数,线程处理函数的开启需要用到信号槽机制。
  6. 关闭线程
    3.2示例程序
/******************mythread.h*************************************/
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QObject>
#include <QThread>
#include <QDebug>

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

    void thread();
    void setflag(bool flag = true);
signals:
    void mysignal();

private:
    bool isStop;


};

#endif // MYTHREAD_H
/***************************mythread.cpp*********************************************/
#include "mythread.h"

mythread::mythread(QObject *parent) : QObject(parent)
{
    isStop = false;
}
void mythread::thread()
{

    while (!isStop)
    {
        QThread::sleep(1);
        emit mysignal();
        qDebug() << "子线程号:" << QThread::currentThread();
        if(isStop) break;
    }

}

void mythread::setflag(bool flag)
{
    isStop = flag;
}
/******************************mywidgt.h************************************************/
#ifndef MYWIDGET_H
#define MYWIDGET_H

#include <QWidget>
#include <mythread.h>
#include <QDebug>
QT_BEGIN_NAMESPACE
namespace Ui { class MyWidget; }
QT_END_NAMESPACE

class MyWidget : public QWidget
{
    Q_OBJECT

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

    mythread *testthread;
    QThread *thread;
signals:
    /*启动子线程的信号*/
        void startsignal();

private slots:
    void on_startPushbutton_clicked();
    void delsignals();
    void on_closePushbutton_clicked();
    void dealclose();
private:
    Ui::MyWidget *ui;
};
#endif // MYWIDGET_H
/************************************mywidgt.cpp*********************************************/
#include "mywidget.h"
#include "ui_mywidget.h"
#include <QThread>

MyWidget::MyWidget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::MyWidget)
{
    ui->setupUi(this);
    /*动态分配空间不能知道父对象*/
    testthread = new mythread();

    /*创建子线程*/
    thread = new QThread(this);

    /*把自定义线程加入到子线程中*/
    testthread->moveToThread(thread);

    connect(testthread, &mythread::mysignal, this, &MyWidget::delsignals);
    qDebug() << "主线程号:" << QThread::currentThread();
    connect(this, &MyWidget::startsignal, testthread, &mythread::thread);

    connect(this, &MyWidget::destroyed, this, &MyWidget::dealclose);
    /*线程函数内部不允许操作图形界面 一般用数据处理
    connect第五个参数作用:
    只有在多线程的时候采意义 连接方式 直接 队列
    默认的时候如果是多线程则使用队列
    单线程使用直接方式
    队列和直接差别:
    队列:槽函数所在的线程和接受者一样
    直接:槽函数所在线程和发送者一样
*/
}

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


void MyWidget::on_startPushbutton_clicked()
{
    if(thread->isRunning() == true)
    {
        return;
    }
    /*启动线程但是没有启动线程处理函数*/
    thread->start();
    /*不能直接调用线程处理函数 直接调用导致线程处理函数和主线程处于同一线程*/
    emit startsignal();
}

void MyWidget::delsignals()
{
    static int i = 0;
    i ++;
    ui->lcdNumber->display(i);

}

void MyWidget::on_closePushbutton_clicked()
{
    if(thread->isRunning() == false)
    {
        return ;
    }

    testthread->setflag();
    thread->quit();
    thread->wait();

}

void MyWidget::dealclose()
{
    /* 释放对象*/
    delete testthread;
    on_closePushbutton_clicked();
}

执行效果如下:
在这里插入图片描述
上述程序当中线程处理函数变成了一个死循环,要想使用quit方式关闭线程,需要注意是无法关闭的因为是一个死循环,所以说quit处于一直等待线程任务结束的状态,但是线程任务是一个死循环,所以无法结束,我们采用一个标志位的方式,需要关闭线程的时候让死循环break退出循环,再关闭线程

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Qt中的线程详解 的相关文章

  • Qt Creator:如何区分 win32 和 win64

    我必须在 pro 文件中执行类似的操作 win32 LIBS L 3rdparty libusb win32 lib msvc llibusb else win64 LIBS L 3rdparty libusb win32 lib msvc
  • Qt中如何获取鼠标在屏幕上的位置?

    我想获取屏幕上的鼠标坐标 我怎样才能在 Qt 中做到这一点 在 Windows 上 使用 C 我正在做类似答案中建议的事情对于这个问题 https stackoverflow com q 11737665 1420197 正如文档所述 QC
  • 如何在带有预编译头的项目中使用google protobuf

    我有一个包含多个项目的解决方案 我的项目 但不是全部 使用预编译头 我决定使用 protobuf 但遇到了一个问题 在 protoc exe 从 proto 生成 pb h 后 我尝试包含标头并收到错误 预编译标头未包含在 pb h 中 我
  • QGraphicsScene::clear 不会改变 sceneRect

    我有一个 QGraphicsScene 场景 和 QGraphicsView graphicsView 我有一个画图的方法 当我需要重绘所有图形时 我调用这个方法 一切都好 但我意识到 scene gt clear 不会改变 sceneRe
  • Qt 文件对话框默认后缀不起作用

    我将以下代码用于 QtQuick Dialogs 1 3 和 Qt 5 10 0 下 filedialog 的新属性 我使用 Qt Creator 5 10 默认套件构建它 import QtQuick 2 10 import QtQuic
  • 如何创建用于 QML 的通用对象模型?

    我想知道是否有任何宏或方法如何将 Qt 模型注册为 QObject 的属性 例如 我有AnimalModel http doc qt io qt 5 qtquick modelviewsdata cppmodels html qabstra
  • 使用 Visual Studio 2013 构建 Qt 5.2.1 的静态版本

    几天来我一直在尝试使用 Visual Studio 2013 构建 Qt 的静态版本 我就是不明白我做错了什么 System Windows 7 64 位 Visual Studio 2013 仍安装 Visual Studio 2012
  • 即使在可访问性中勾选应用程序,AXIsProcessTrustedWithOptions 也不会返回 true

    As this question https stackoverflow com questions 17693408 enable access for assistive devices programmatically on 10 9
  • QT从QTableWidgetItem继承到Widget并覆盖'<'运算符

    我想要一个QTableWidget具有定制的某些单元QProgressBars 并且我希望能够对包含这些的列进行排序 我的定制QProgressBar继承自两者QProgressBar and QTableWidgetItem 并且我正在覆
  • 如何检测QTableView中的双击

    我正在使用 PyQt 创建 GUI 应用程序 在继承自 QTableView 的视图中 需要检测用户双击行时选择的行 该表可以排序 但不能编辑 我该怎么做 注意 尝试了 doubleClicked int 信号 它是由鼠标按钮发出的 而不是
  • 同时从多个流中捕获、最佳方法以及如何减少 CPU 使用率

    我目前正在编写一个应用程序 该应用程序将捕获大量 RTSP 流 在我的例子中为 12 个 并将其显示在 QT 小部件上 当我超过大约 6 7 个流时 问题就会出现 CPU 使用率激增并且出现明显的卡顿 我认为它不是 QT 绘制函数的原因是因
  • 如何使用meta-toolchain-qt5构建Qt(带有QtWebEngine支持)?

    我正在尝试使用构建 Qtmeta toolchain qt5 但是当我通过这样做时poky glibc x86 64 meta toolchain qt5 cortexa7hf vfp vfpv4 neon toolchain 2 0 1
  • Qt表格小部件,删除行的按钮

    我有一个 QTableWidget 对于所有行 我将一列的 setCellWidget 设置为按钮 我想将此按钮连接到删除该行的函数 我尝试了这段代码 它不起作用 因为如果我只是单击按钮 我不会将当前行设置为按钮的行 ui gt table
  • 将 QByteArray 从大端转换为小端

    我想我在这里有点不知所措 我尝试了这么简单的事情 我不敢相信没有任何内置的 Qt 使用 Qt 5 6 2 我尝试将 QByteArray 内的数据从大端转换为小端 总是从相同的测试 QByteArray 开始 就像这样 QByteArray
  • Qt GUI 应用程序中的控制台输出?

    我有一个在 Windows 上运行的 Qt GUI 应用程序 它允许传递命令行选项 在某些情况下我想向控制台输出一条消息 然后退出 例如 int main int argc char argv QApplication a argc arg
  • 来自另一个类的 Qt C++ GUI 调用

    我通过 gui 拖放创建了一个按钮和一个文本浏览器 UI 以及单击按钮功能是在 mainwindow cpp 中创建的 有一个 main cpp 但这是无关紧要的 因为在单击开始按钮之前程序不会启动 include mainwindow h
  • 如何从 matlab 调用 Qtproject?

    我在 matlab 中有一个函数可以写入一个 file txt 我在 qt 项目中使用它 So 当我使用 unix 获取要运行的 qt 编译可执行文件时 我有一个 Matlab 文件 但出现错误 代码 unix home matt Desk
  • 使用 PyQt 和 matplotlib 在可滚动小部件中显示多个绘图

    由于我没有得到答案this https stackoverflow com questions 12179893 creating a scrollable multiplot with pythons pylab我尝试用 PyQt 解决这
  • Qt Creator 2.8.1 Qt 5.1.1 Qt Designer Linux 显示新窗体

    我是 Qt 的初学者 所以希望这是一个容易回答的问题 我有相当多的 C 经验 这部分不是问题 我的应用程序的目的是进行代码生成 最初是为类制作头文件和实现文件 我非常喜欢 Code Blocks 上的类向导 但我认为我可以做更多的事情 我有
  • 使用 Qt 的网络服务

    我正在寻找使用 Qt 服务器端 实现 Web 服务的代码 如果您有任何信息 我将不胜感激 Regards 您可以使用libqxt http libqxt bitbucket org doc 0 6 qxtweb html实现服务器端Web服

随机推荐

  • 02_Numpy学习笔记(下):随机采样

    02 Numpy学习笔记 下 随机采样 文章目录 02 Numpy学习笔记 下 随机采样 一 离散型随机变量的分布 1 二项分布 2 泊松分布 3 超几何分布 二 连续型随机变量的分布 1 均匀分布 2 正态分布 3 指数分布 三 其他随机
  • 华为OD机试真题 Java 实现【日志采集系统】【2023Q1 100分】,附详细解题思路

    目录 一 题目描述 二 输入描述 三 输出描述 四 解题思路 五 Java算法源码 六 效果展示 1 输入 2 输出 3 说明 一 题目描述 日志采集是运维系统的的核心组件 日志是按行生成 每行记做一条 由采集系统分批上报 如果上报太频繁
  • Python装饰器探究

    说在前边 装饰器作为Python中的一个比较实用的东西 在我们日常库的使用过程中经常使用 但是其细节问题我们却常常忘记考虑 本文章就此问题写建装饰器代码来进行一步一步分析 装饰器实验 1 我们常见的装饰器使用方式 from functool
  • ROS激光SLAM导航理解

    ROS激光SLAM导航理解 注 最近学习ROS的激光导航知识 需要理清ROS的SLAM 环境感知 costmap 与导航算法 为防止自己忘记 将觉得有价值的内容收集于此 对AGV来说 SLAM是个大大坑 环境感知和局部运动控制也是大坑 学习
  • 数据库添加/删除/修改 表字段(超详细)

    Oracle 添加 删除 修改 表字段 超详细 1 添加表字段 1 1 语法结构 1 2 举例说明 1 新建学生信息表 该步骤可忽略 2 初始表样子 3 语法解释 2 修改表字段 2 1 语法结构 1 修改字段属性 2 修改字段名 2 2
  • games101课程作业,在Vs2019环境下的配置环境(不使用虚拟机)

    为什么不使用虚拟机 因为虚拟机使用ubuntu x64版本系统 是一个从未接触过的系统 不好使用 虚拟机中无法使用中文输入法 无法对代码进行注释 不利于学习 虚拟机性能差 打开两三个文件就卡 令人抓狂 要使用终端进行编译 很是麻烦 还是喜欢
  • 面试经典-不被忽略的@property

    我们都知道 property是用来声明属性的 可以保存类的状态或信息 而与其相关的内容 诸如copy weak 深拷贝等 经常会在面试的过程中出现 接下来深入下这些模糊 熟悉的内容 理理顺 内容概要 1 property的本质 2 自动合成
  • Profinet 的交互流程

    Profinet 的交互流程 启动过程 在启动Profinet IO设备时 在设置IP地址之前 使用DCP协议 该协议类似于DHCP协议 PLC发送DCP广播消息 Identify 子网上的所有IO设备都使用本身的MAC地址进行应答 PLC
  • 机器学习算法与Python实践之(六)二分k均值聚类

    机器学习算法与Python实践之 六 二分k均值聚类 zouxy09 qq com http blog csdn net zouxy09 机器学习算法与Python实践这个系列主要是参考 机器学习实战 这本书 因为自己想学习Python 然
  • 基于IDEA的Java学生管理系统

    1 创建学生类 package studentManager public class Student 定义成员变量 private String num 学号 private String name 姓名 private String a
  • 善用Linux内核中的各种数据结构和算法

    1 介绍 在数据结构和算法一文中经常就信手拈来一些基本数据结构和算法 如链表 队列 栈 二叉树等等 但是在C的标准库中并没有自带这些 C 通过STL 类程序库等等会带这些 那么在嵌入式开发里面怎么快速方便使用这些数据结构和算法咧 答案就是从
  • OpenGL 理解GL_TRIANGLE_STRIP等绘制三角形序列的三种方式

    OpenGL 理解GL TRIANGLE STRIP等绘制三角形序列的三种方式 2012 04 12 20 19 19389人阅读 评论 7 收藏 举报 GL TRIANGLE STRIP绘制三角形方式很多时候令人疑惑 在这里对其运作机理进
  • 【Java基础·Comparator多字段排序】

    Java基础 Comparator多字段排序 需求 对指定List按照 身份证号 姓名 入学时间倒序排列 版本1 package com biaogexf tools import lombok Data import java util
  • 游戏开发unity杂项知识系列:GameObject组件的SetActive、active、activeSelf与activeInHierarchy

    SetActive 控制物体的显示状态 SetActive true 物体设置为可显示状态 但是仍然依赖上层的显示状态 上层显示状态为可显示才能显示 SetActive false 物体设置为不可显示状态 active 在某个版本后已经弃用
  • Python标准库----random

    目录 一 简单认识random模块 二 本人对计算机中 随机 伪随机数 的理解和认识 三 random模块的常用方法 1 random seed 2 其余一些常用方法 四 参考文献 一 简单认识random模块 Python官网的解释 该模
  • SASS用法指南

    学过CSS的人都知道 它不是一种编程语言 你可以用它开发网页样式 但是没法用它编程 也就是说 CSS基本上是设计师的工具 不是程序员的工具 在程序员眼里 CSS是一件很麻烦的东西 它没有变量 也没有条件语句 只是一行行单纯的描述 写起来相当
  • 基于DC-DC的PWM控制器simulink仿真,包括abc转dq,PI控制器等

    目录 1 算法仿真效果 2 MATLAB源码 3 算法概述 1 引言 2 基本原理 2 1 脉宽调制 PWM
  • [C# 开发技巧系列] 使用C#操作幻灯片

    本专题概要 引言 实现思路 遥控幻灯片程序的实现 小结 一 引言 记得老师讲课的时候 经常会用PPT遥控翻页笔来遥控幻灯片来给我们讲课 当时觉得非常有趣 由于这段时间接触了VSTO相关的开发 了解到了Office的相关产品都公开了一些API
  • 三菱m80润滑参数_三菱第四轴的开通及设定

    M70与M80 均是标配第四轴功能的 不需要开通选项功能 a 开通第四轴功能 1002 4按下急停按钮 点击机台关机电源 关闭机床总电源 再开启机床总电源 再开机 b 定义第四轴名称 1013 A 第四轴名称为A c 格式化 使上述参数设定
  • Qt中的线程详解

    概述 在多核时代 CPU 的主频已经进入瓶 颈 另辟蹊径地提高程序运行效率就是使用线程 充分利用多核的优势 线程可以看做是 轻量级进程 线程即可以由操作系统管理 也可以由应用程序管 1 为什么要使用线程 我们都知道 进程线程的概念是非常重要