Qt实现多线程编程的两种方式

2023-10-26

Qt实现多线程编程的两种方式


方式一: 继承自QThread类,覆写run函数。此实现方法只有run函数内的代码是运行在子线程内。

代码示例:

#ifndef QDEMOTHREAD_H
#define QDEMOTHREAD_H

#include <QThread>
#include <QDebug>

class QDemoThread : public QThread
{
    Q_OBJECT

public:
    QDemoThread(QObject* parent = nullptr);
    ~QDemoThread();

protected:
    void run() override;

public:
    void stop();

private:
    bool flag;
};

#endif // QDEMOTHREAD_H

#include "qdemothread.h"

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

}

QDemoThread::~QDemoThread()
{

}

void QDemoThread::run()
{
    flag = true;
    while(flag)
    {
        qDebug() << "thread id:" << QThread::currentThreadId();
        sleep(1);
    }
}

void QDemoThread::stop()
{
    flag = false;
    if(isRunning())
    {
        exit();  // 结束线程
        wait();  // 等待退出
    }
}


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

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    demoThread = new QDemoThread(this);

    qDebug() << "main thread id:" << QThread::currentThreadId();
}

Widget::~Widget()
{
    demoThread->stop();  // 退出线程
    delete ui;
}

void Widget::on_pushButton_clicked()
{
    if(!demoThread->isRunning())
    {
        demoThread->start();  // 启动线程
    }
}

运行效果:
在这里插入图片描述


方式二: 创建一个QThread和QWorker(继承自QObject)类对象,使用moveToThread函数移动到thread中运行,通过thread类start信号和worker的init槽函数绑定,init槽函数内是一些初始化操作,然后定义个定时器,周期触发doWork()。

网上有很多教程是在doWork()中使用while(isRunning)死循环的形式,不建议这么干,如果线程一直在doWork中死循环,那么他是无法接收到来自外部的信号的。推荐的方法是用定时器周期触发。

示例代码:

QWorker类:

#ifndef QWORKER_H
#define QWORKER_H

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

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

signals:
    void newData(QByteArray data);    // 将本类内的私有数据通过该信号发射出去,供外部使用

public slots:
    void init();         // 一些必要的初始化操作写在此函数内
    void doWork();       // 一些耗时操作写在此函数内
    void writeData(const char* buf, qint64 len);  // 供外部使用的操作接口
};

#endif // QWORKER_H

#include "qworker.h"

QWorker::QWorker(QObject *parent) : QObject(parent)
{
    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId();
}

QWorker::~QWorker()
{
    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId();
}

void QWorker::init()
{
    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId();
}

void QWorker::doWork()
{
    static int count = 0;
    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId() << ">>>" << count++;
}

void QWorker::writeData(const char* buf, qint64 len)
{
    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId() << ">>>" << QByteArray(buf, len);
}


主线程:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "qworker.h"
#include <QTimer>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();

private:
    Ui::MainWindow *ui;
    QWorker* worker;
    QThread* thread;
    QTimer* timer;

signals:
    void writeData(const char* buf, qint64 len);
    void stopWork();
};

#endif // MAINWINDOW_H

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId();

    timer = new QTimer(this);

    thread = new QThread();  // 不要指定parent
    worker = new QWorker();  // 不要指定parent

	// thread的finished和deleteLater相连接后,在thread退出时自动删除thread对象,无需手动delete thread
    connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); 
    // thread的finished和worker的deleteLater相连接后,在thread退出时自动删除worker对象,无需手动delete worker
    connect(thread, SIGNAL(finished()), worker, SLOT(deleteLater()));
    connect(thread, SIGNAL(started()), worker, SLOT(init()));

    connect(timer, SIGNAL(timeout()), worker, SLOT(doWork()));

    connect(this, SIGNAL(writeData(const char*,qint64)), worker, SLOT(writeData(const char*,qint64)));

    worker->moveToThread(thread);

    thread->start();

    timer->start(1000);  // 1000ms执行一次doWork()
}

MainWindow::~MainWindow()
{
    if(timer->isActive())
    {
        timer->stop();
    }

    if(thread->isRunning())
    {
        thread->quit();
        thread->wait();
    }

    qDebug() << __FUNCTION__ << "Thread ID:" << QThread::currentThreadId();

    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    emit writeData("hello world\r\n", 13);
}


程序界面:

运行后控制台打印信息如下:

可以看到的是,MainWindow和QWorker的构造函数中都显示线程ID为0x336c,而在QWorker的析构函数中显示线程ID为0x22a8,这说明moveToThread确实将worker移动到了thread中;而且还可以看到的是,QWorker的槽函数init、doWork、writeData也都是运行在了子线程中!


ends…

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

Qt实现多线程编程的两种方式 的相关文章

  • 将信号/槽(QObject)添加到 QGraphicsItem:性能受到影响?

    我想将信号 槽添加到 QGraphicsItem 以便我可以从另一个线程访问 QGraphicsItemObjects 我知道有两个选项 使用 QGraphicsObject 或从 QObject 和 QGraphicsItem 继承 使用
  • 如何找到 QDockWidget 标题栏的高度?

    我正在尝试找到 a 的高度QDockWidget标题栏 以便对自定义布局进行一些智能调整大小 但标题栏不是单独的小部件 它内置于停靠小部件的私有布局中 并且没有成员可以访问它 还有其他方法可以找到它的高度吗 是的 您可以使用以下命令找到标题
  • 如何使用 Qt Test 控制 QFileDialog?

    我有两个问题 我怎样才能访问QFileDialog并使用 Qt Test 模块在 文件名 字段中写入文件的路径 我这么问是因为我正在 Qt 中开发一些 GUI 测试 现在我需要打开一个文本文件 以下代码创建QFileDialog并获取文件路
  • 删除 QComboBox“下拉”动画

    我正在使用 Qt 4 8 并且想在单击 QComboBox 时摆脱 下拉 动画 我也想稍微移动一下 到目前为止 我一直在考虑重新实现 showPopup 和 hidePopup 但不知道如何使其工作 此外 每次我尝试使用 CSS 进行移动或
  • Qt 信号槽,新符号中的转换类型[重复]

    这个问题在这里已经有答案了 鉴于以下两个 connect ui gt comboBox SIGNAL activated QString ps SLOT requestPlotsAvailable QString connect ui gt
  • 如何在 QTableWidget 的行和列中自动换行文本?

    I tried QTableWidget j new QTableWidget 10000 5 centralWidget j gt setColumnWidth 0 500 j gt setColumnWidth 1 30 j gt se
  • 检查目录是否为空

    我正在尝试检查目录是否为空 MainWindow MainWindow QWidget parent QMainWindow parent ui new Ui MainWindow ui gt setupUi this QDir Dir h
  • 对齐坐标系

    Let s say I have 2 coordinate systems as it is shown in image attached 如何对齐这个坐标系 我知道我需要将第二个坐标系围绕 X 平移 180 度 然后将其平移到第一个坐标
  • 调整 QML 图像显示尺寸

    我有一个带有嵌套的 QML 窗口RowLayout 在内排我有两个图像 来源 png这些图像的文件 故意 相当大 当我尝试设置height这些图像上的属性使它们变小 但它们仍然被画得很大 Desired Appearance Actual
  • qt项目如何设置安装路径

    我正在寻找与 qmake configure prefix 等效的内容 基本上 我想覆盖默认的安装 部署目录 这是如何用命令行 qmake 指定的 我还使用 QtCreator 构建了很多 gui 项目 并且我想知道如何在 QtCreato
  • 如何在 Qt-Embedded 中(正确)输出多语言文本?

    我的目标系统是 linux 3 3 7 Qt Embedded 开源版 4 8 Droid 字体 取自 fonts droid 20111207 git 1 all deb Debian 软件包并复制到 usr lib fonts目录 主要
  • Qt/c++ 随机字符串生成[重复]

    这个问题在这里已经有答案了 我正在创建一个应用程序 需要生成多个随机字符串 几乎就像一个由一定长度的 ASCII 字符组成的唯一 ID 这些字符混合有大写 小写 数字字符 有没有 Qt 库可以实现这一点 如果没有 在纯 C 中生成多个随机字
  • 当我尝试构建 Qt 4.7.1 静态库时,“找不到 -ljscore”

    我尝试从最新的源构建静态 Qt 库 但出现以下错误 usr bin ld cannot find ljscore collect2 ld returned 1 exit status 如何解决这个问题呢 这是 Qt 构建系统中自 4 7 0
  • Qt:将拖放委托给子级的最佳方式

    我在 QWidget 上使用拖放 我重新实现了 DragEnterEvent dragLeaveEvent dragMoveEvent 和 dropEvent 效果很好 在我的 QWidget 中 我有其他 QWidget 子级 我希望它们
  • QtCreator 调试暂停停在代码而不是汇编处

    如何配置 QtCreator 以便在调试并按下暂停时它会显示当前正在处理的代码 现在显示汇编 无法在任何地方找到有关此问题的答案 我使用的是 Windows 7 我在 Ubuntu 16 04 中使用 Qt Creator 4 2 2 时遇
  • QTextEdit.find() 在 Python 中不起作用

    演示问题的简单代码 usr bin env python import sys from PyQt4 QtCore import QObject SIGNAL from PyQt4 QtGui import QApplication QTe
  • 如何使用 Qtimer 添加 1 秒延迟

    我目前有一个方法如下 void SomeMethod int a Delay for one sec timer gt start 1000 After one sec SomeOtherFunction a 这个方法实际上是一个附加到信号
  • 加权 Voronoi 的 CGAL 2D APOLLONIUS 图 - 如何生成和获取面和顶点?

    我正在尝试根据阿波罗尼乌斯图生成加权沃罗诺伊 我正在使用 CGAL 库 我找不到如何从 apollonius 获取面和顶点的好例子 我有以下类型定义 typedef double NT typedef CGAL Cartesian lt N
  • 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

随机推荐

  • JavaWeb——Servlet(入门必备,web请求与响应的底层)

    这里写自定义目录标题 1 servlet介绍 1 1 什么是servlet 1 2 手动实现servlet程序的步骤 2 servlet的生命周期 3 get请求与post请求的分发 3 1 get请求 3 2 post请求 3 3 通过继
  • MASK R-CNN网络介绍

    目录 前言 一 MASK R CNN网络 1 1 RoIPool和RoIAlign 1 2 MASK分支 二 损失函数 三 Mask分支预测 前言 在介绍MASK R CNN之前 建议先看下FPN网络 Faster R CNN和FCN的介绍
  • python数据可视化入门(五):饼图,环图,极线图,气泡图

    饼图 plt pie x explode None labels None colors None autopct None 1 labels 设置相对应数据的标签 2 labeldistance 设置标签距离圆心的距离 labeldist
  • 【C++ Primer Plus(第6版)中文版第二章开始学习C++(编程练习题)】

    关于个人学习C Primer Plus的第二章编程练习题 1 编写一个C 程序 它显示您的姓名和地址 2 编写一个C 程序 它要求用户输入一个以long为单位的距离 然后将它转换为码 一long等于220码 3 编写一个C 程序 它使用3个
  • CTF_webshow_web11

    d打开靶机 直接有源码 查看一下
  • Java Swing 经典小游戏之 ———— 黄金矿工

    一 效果预览 项目简介 1 游戏预览 2 玩法简介 1 开局一条红绳 左键让他变长 2 5个金块 分成 大中小 3个石块 3 3种速度 空爪 gt 抓回金块 gt 抓回石块 4 4个得分 获得 得分 大金块 30 中金块 20 小金块 10
  • MCU踩坑记录:SWD复用为GPIO使用,Jflash连不上的问题

    用了某款MCU 由于项目需要用的gpio比较多 只能将SWD烧写口SWD CLK和SWD DIO复用为gpio使用 但是程序一旦跑起来 再用jflash就连不上了 如下图所示 如果MCU有BOOT引脚 可以将BOOT引脚配置为其他启动模式不
  • vue脚手架如何创建vue项目

    vue脚手架如何创建vue项目 1 打开命令行 进入需要创建目录的文件夹 或者在需要创建目录的文件夹进入cmd窗口 1 先查看以下vue脚手架是否下载 命令行输入npm list g 1 2 如果没下载vue脚手架 则输入命令npm ins
  • Java开发人员必知必会的20种常用类库和API

    Java开发人员必知必会的20种常用类库和API 一个有经验的Java开发人员特征之一就是善于使用已有的轮子来造车 Effective Java 的作者Joshua Bloch曾经说过 建议使用现有的API来开发 而不是重复造轮子 在本文中
  • Spring cloud Gateway常用配置

    gateway里的常用配置 前面的例子是通过路径 Path 方式配置路由转发 gateway还还有其他的配置 下面做个简单的介绍 1 路由 route Route 主要由 路由id 目标uri 断言集合 过滤器集合组成 前面的实例用到了id
  • python 获取网页视频

    代码实现 import tkinter import tkinter messagebox import os import os path import you get 获取当前工作目录 path os getcwd 设置当前目录为工作目
  • LeetCode 460. LFU Cache

    原题网址 https leetcode com problems lfu cache Design and implement a data structure for Least Frequently Used LFU cache It
  • 吐血推荐那些提升开发人员工作效率的在线工具

    来源 公众号 作者 Hollis 作为一个Java开发人员 经常要和各种各样的工具打交道 除了我们常用的IDE工具以外 其实还有很多工具是我们在日常开发及学习过程中要经常使用到的 Hollis偏爱使用在线工具 因为个人觉得这样比较方便 本文
  • crontab定时启动scrapy爬虫

    部署到测试环境 并设置定时启动任务 通过FileZille工具 将本地的文件上传到测试服务器上面的python文件夹中 在与spider同级目录下写一个shell脚本 启动所编辑的运行爬虫文件 vi run sh 1 bin sh 2 ex
  • 修改服务器数据库名称,修改服务器数据库名称

    修改服务器数据库名称 内容精选 换一换 弹性云服务器能否ping通华为云关系型数据库实例 如果ping不通 可以查看弹性云服务器和华为云关系型数据库实例是否处于同一个虚拟私有云内 是否使用同一个安全组 如果ping不通 可以查看弹性云服务器
  • Aviator这么丝滑,怎么实现的呢?

    大家好 我是老三 在上期 里我们介绍了轻量级规则引擎AviatorScript的基本用法和一些使用案例 这期我们来研究一下 这么丝滑的规则脚本是怎么实现的 概览 我们先来回顾一个简单的例子 Test public void test 表达式
  • element 模态框内,表单编辑回填的值在关闭时,表单内容无法正确重置问题

    element 表单使用 this refs formName resetFields 进行数据重置 但重置的初始数据是基于表单第一次渲染时的数据为模板 由于点击编辑时 模态框显示与表单内容渲染是同时进行 所以 el form 就认为回填值
  • STM32--TIM定时器(3)

    文章目录 输入捕获简介 频率测量 输入捕获通道 输入捕获基本结构 PWMI的基本结构 输入捕获模式测量PWM频率和占空比 代码 编码器接口 正交编码器 工作模式 接口基本结构 TIM编码接口器测速 代码 输入捕获简介 输入捕获IC Inpu
  • 传奇服务器文件组成,【教程】传奇服务端(版本)的结构以及重要文件功能的概述-A02...

    第A02课 传圌奇私圌服服圌务端 版本 的结构以及重要文件功能的概述 有很多新人根本不了解传圌奇的结构 学习的时候就比较困难 所以才设置了这么一课 以下是服圌务端主要文件位置与用途
  • Qt实现多线程编程的两种方式

    Qt实现多线程编程的两种方式 方式一 继承自QThread类 覆写run函数 此实现方法只有run函数内的代码是运行在子线程内 代码示例 ifndef QDEMOTHREAD H define QDEMOTHREAD H include