我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Qt中的线程怎么应用

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Qt中的线程怎么应用

今天小编给大家分享一下Qt中的线程怎么应用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

1、多线程操作UI界面的示例

下面,是一个使用多线程操作UI界面的示例 - 更新进度条,采用子类化QThread的方式。与此同时,分享在此过程中有可能遇到的问题及解决方法。

Qt中的线程怎么应用

首先创建QtGui应用,工程名称为“myThreadBar”,类名选择“QMainWindow”,其他选项保持默认即可。再添加一个名称为WorkerThread的头文件,定义一个WorkerThread类,让其继承自QThread,并重写run()函数,修改workerthread.h文件如下:

#ifndef WORKERTHREAD_H#define WORKERTHREAD_H #include <QThread>#include <QDebug> class WorkerThread : public QThread{    Q_OBJECT public:    explicit WorkerThread(QObject *parent = 0)        : QThread(parent)    {        qDebug() << "Worker Thread : " << QThread::currentThreadId();    } protected:    virtual void run() Q_DECL_OVERRIDE    {        qDebug() << "Worker Run Thread : " << QThread::currentThreadId();        int nValue = 0;        while (nValue < 100)        {            // 休眠50毫秒            msleep(50);            ++nValue;             // 准备更新            emit resultReady(nValue);        }    } signals:    void resultReady(int value);}; #endif // WORKERTHREAD_H

通过在run()函数中调用msleep(50),线程会每隔50毫秒让当前的进度值加1,然后发射一个resultReady()信号,其余时间什么都不做。在这段空闲时间,线程不占用任何的系统资源。当休眠时间结束,线程就会获得CPU时钟,将继续执行它的指令。

再在mainwindow.ui上添加一个按钮和进度条部件,然后mainwindow.h修改如下:

#ifndef MAINWINDOW_H#define MAINWINDOW_H #include <QMainWindow>#include "workerthread.h" namespace Ui {class MainWindow;} class MainWindow : public QMainWindow{    Q_OBJECT public:    explicit MainWindow(QWidget *parent = nullptr);    ~MainWindow(); private slots:    // 更新进度    void handleResults(int value);     // 开启线程    void startThread(); private:    Ui::MainWindow *ui;     WorkerThread m_workerThread;}; #endif // MAINWINDOW_H

然后mainwindow.cpp修改如下:

#include "mainwindow.h"#include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) :    QMainWindow(parent),    ui(new Ui::MainWindow){    ui->setupUi(this);            qDebug() << "Main Thread : " << QThread::currentThreadId();             // 连接信号槽    this->connect(ui->pushButton, SIGNAL(clicked(bool)), this, SLOT(startThread()));} MainWindow::~MainWindow(){    delete ui;} void MainWindow::handleResults(int value){    qDebug() << "Handle Thread : " << QThread::currentThreadId();    ui->progressBar->setValue(value);} void MainWindow::startThread(){    WorkerThread *workerThread = new WorkerThread(this);    this->connect(workerThread, SIGNAL(resultReady(int)), this, SLOT(handleResults(int)));    // 线程结束后,自动销毁    this->connect(workerThread, SIGNAL(finished()), workerThread, SLOT(deleteLater()));    workerThread->start();}

由于信号与槽连接类型默认为“Qt::AutoConnection”,在这里相当于“Qt::QueuedConnection”。也就是说,槽函数在接收者的线程(主线程)中执行。

执行程序,“应用程序输出”窗口输出如下:

Main Thread :  0x3140
Worker Thread :  0x3140
Worker Run Thread :  0x2588
Handle Thread :  0x3140

显然,UI界面、Worker构造函数、槽函数处于同一线程(主线程),而run()函数处于另一线程(次线程)。

2、避免多次connect

当多次点击“开始”按钮的时候,就会多次connect(),从而启动多个线程,同时更新进度条。为了避免这个问题,我们先在mainwindow.h上添加私有成员变量"WorkerThread m_workerThread;",然后修改mainwindow.cpp如下:

#include "mainwindow.h"#include "ui_mainwindow.h" MainWindow::MainWindow(QWidget *parent) :    QMainWindow(parent),    ui(new Ui::MainWindow){    ui->setupUi(this);     // 连接信号槽    this->connect(ui->pushButton, SIGNAL(clicked(bool)), this, SLOT(startThread()));     this->connect(&m_workerThread, SIGNAL(resultReady(int)), this, SLOT(handleResults(int)));} MainWindow::~MainWindow(){    delete ui;} void MainWindow::handleResults(int value){    qDebug() << "Handle Thread : " << QThread::currentThreadId();    ui->progressBar->setValue(value);} void MainWindow::startThread(){    if (!m_workerThread.isRunning())        m_workerThread.start();}

不再在startThread()函数内创建WorkerThread对象指针,而是定义私有成员变量,再将connect添加在构造函数中,保证了信号槽的正常连接。在线程start()之前,可以使用isFinished()和isRunning()来查询线程的状态,判断线程是否正在运行,以确保线程的正常启动。

3、优雅地结束线程的两种方法

如果一个线程运行完成,就会结束。可很多情况并非这么简单,由于某种特殊原因,当线程还未执行完时,我们就想中止它。

不恰当的中止往往会引起一些未知错误。比如:当关闭主界面的时候,很有可能次线程正在运行,这时,就会出现如下提示:

QThread: Destroyed while thread is still running

这是因为次线程还在运行,就结束了UI主线程,导致事件循环结束。这个问题在使用线程的过程中经常遇到,尤其是耗时操作。大多数情况下,当程序退出时,次线程也许会正常退出。这时,虽然抱着侥幸心理,但隐患依然存在,也许在极少数情况下,就会出现Crash。

所以,我们应该采取合理的措施来优雅地结束线程,一般思路:

  • 发起线程退出操作,调用quit()或exit()。

  • 等待线程完全停止,删除创建在堆上的对象。

  • 适当的使用wait()(用于等待线程的退出)和合理的算法。

方法一

这种方式是Qt4.x中比较常用的,主要是利用“QMutex互斥锁 + bool成员变量”的方式来保证共享数据的安全性。在workerthread.h上继续添加互斥锁、析构函数和stop()函数,修改如下:

#ifndef WORKERTHREAD_H#define WORKERTHREAD_H #include <QThread>#include <QMutexLocker>#include <QDebug> class WorkerThread : public QThread{    Q_OBJECT public:    explicit WorkerThread(QObject *parent = 0)        : QThread(parent),          m_bStopped(false)    {        qDebug() << "Worker Thread : " << QThread::currentThreadId();    }     ~WorkerThread()    {        stop();        quit();        wait();    }     void stop()    {        qDebug() << "Worker Stop Thread : " << QThread::currentThreadId();        QMutexLocker locker(&m_mutex);        m_bStopped = true;    } protected:    virtual void run() Q_DECL_OVERRIDE     {        qDebug() << "Worker Run Thread : " << QThread::currentThreadId();        int nValue = 0;        while (nValue < 100)        {            // 休眠50毫秒            msleep(50);            ++nValue;             // 准备更新            emit resultReady(nValue);             // 检测是否停止            {                QMutexLocker locker(&m_mutex);                if (m_bStopped)                    break;            }            // locker超出范围并释放互斥锁        }    }    signals:    void resultReady(int value); private:    bool m_bStopped;    QMutex m_mutex;}; #endif // WORKERTHREAD_H

当主窗口被关闭,其“子对象”WorkerThread也会析构调用stop()函数,使m_bStopped变为true,则break跳出循环结束run()函数,结束进程。当主线程调用stop()更新m_bStopped的时候,run()函数也极有可能正在访问它(这时,他们处于不同的线程),所以存在资源竞争,因此需要加锁,保证共享数据的安全性。

为什么要加锁?

很简单,是为了共享数据段操作的互斥。避免形成资源竞争的情况(多个线程有可能访问同一共享资源的情况)。

方法二

Qt5以后,可以使用requestInterruption()、isInterruptionRequested()这两个函数,使用很方便,修改workerthread.h文件如下:

#ifndef WORKERTHREAD_H#define WORKERTHREAD_H #include <QThread>#include <QMutexLocker>#include <QDebug> class WorkerThread : public QThread{    Q_OBJECT public:    explicit WorkerThread(QObject *parent = nullptr)        : QThread(parent)    {        qDebug() << "Worker Thread : " << QThread::currentThreadId();    }     ~WorkerThread()    {        // 请求终止        requestInterruption();        quit();        wait();    } protected:    virtual void run() Q_DECL_OVERRIDE    {        qDebug() << "Worker Run Thread : " << QThread::currentThreadId();        int nValue = 0;         // 是否请求终止        while (!isInterruptionRequested())        {            while (nValue < 100)            {                // 休眠50毫秒                msleep(50);                ++nValue;                 // 准备更新                emit resultReady(nValue);            }        }     }signals:    void resultReady(int value);}; #endif // WORKERTHREAD_H

在耗时操作中使用isInterruptionRequested()来判断是否请求终止线程,如果没有,则一直运行;当希望终止线程的时候,调用requestInterruption()即可。这两个函数内部也使用了互斥锁QMutex。

以上就是“Qt中的线程怎么应用”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Qt中的线程怎么应用

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Qt中的线程怎么应用

今天小编给大家分享一下Qt中的线程怎么应用的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。1、多线程操作UI界面的示例下面,是
2023-07-05

一文详解Qt中线程的实际应用

为了让程序尽快响应用户操作,在开发应用程序时经常会使用到线程。这篇文章就来和大家介绍一下Qt中线程的实际应用,感兴趣的小伙伴可以了解一下
2023-03-10

详解Qt中线程的使用方法

这篇文章主要为大家详细介绍了Qt中线程的使用方法,文中的示例代码讲解详细,对我们学习Qt有一定的帮助,感兴趣的小伙伴可以跟随小编一起了解一下
2022-12-16

qt怎么开启多个线程

在Qt中,可以使用QThread类来开启多个线程。下面是一个简单的示例代码:```cpp#include #include class WorkerThread : public QThread {public:void run() ove
2023-09-22

QT中TerminateThread不能结束线程怎么解决

在QT中,TerminateThread函数不能安全地结束线程,因为它会导致线程突然终止,可能会导致资源泄露或者死锁的情况发生。相反,应该使用其他方法来正确地结束线程。一种解决方法是使用线程取消请求。在QT中,可以使用QThread::r
QT中TerminateThread不能结束线程怎么解决
2024-02-29

qt子线程怎么向主线程发送信号

在Qt中,子线程不能直接与主线程通信,因为Qt是基于事件循环机制的。一般情况下,需要借助信号和槽机制来实现子线程向主线程发送信号。以下是一种常见的方法:1. 定义一个自定义信号类,例如MySignal,继承自QObject。2. 在子线程中
2023-09-13

qt线程抢占问题怎么解决

Qt线程抢占问题指的是多个线程同时访问共享资源时可能导致的数据竞争和不确定性的问题。下面是一些解决Qt线程抢占问题的方法:使用互斥锁(QMutex)或读写锁(QReadWriteLock)来保护共享资源。在访问共享资源之前,先获取互斥锁或读
qt线程抢占问题怎么解决
2024-02-29

python多线程怎么应用

本篇内容主要讲解“python多线程怎么应用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“python多线程怎么应用”吧!一、首先定义一个封装类,主要是保证PyGILState_Ensure,
2023-06-17

C++ 多线程编程中线程池的应用

c++++ 多线程编程中使用线程池的好处包括:1)减少线程创建次数;2)负载均衡;3)避免资源争用。例如,通过使用线程池将图像转换任务分配给线程池,可以提高文件转换应用程序的转换速度。C++ 多线程编程中线程池的应用在现代 C++ 应用程
C++ 多线程编程中线程池的应用
2024-05-14

qt的信号槽跨线程程序崩溃怎么解决

当信号槽跨线程时,Qt提供了一些机制来确保线程安全。如果你的程序在使用跨线程的信号槽时崩溃了,你可以尝试以下方法来解决问题:1. 使用Qt::QueuedConnection连接模式:当信号槽对象位于不同的线程时,你可以使用Qt::Queu
2023-10-18

java多线程在项目中怎么应用

Java多线程在项目中的应用主要有以下几个方面:1. 提高程序的并发性:多线程可以同时处理多个任务,提高程序的并发性,使得程序的执行效率更高。2. 实现异步操作:多线程可以实现异步操作,将耗时的操作放在后台线程中执行,避免阻塞主线程,提高用
2023-09-29

java虚拟线程怎么应用

Java虚拟线程的应用Java虚拟线程提供高性能、可伸缩性和隔离性,非常适合I/O密集型、计算密集型和事件处理任务。通过轻量级的线程创建和销毁,虚拟线程可优化微服务、游戏开发和并发编程。JavaAPI提供易于使用的创建、管理和调度功能,而其用户空间实现则保证了效率和可扩展性。最佳实践包括避免阻塞、限制线程数量、使用线程池和监控性能。
java虚拟线程怎么应用
2024-04-11

java虚拟线程怎么应用

Java虚拟线程,即Java虚拟机(JVM)中的线程,可以通过以下几种方式应用:1. 多线程编程:Java提供了多线程编程的支持,可以通过创建线程对象、实现Runnable接口或继承Thread类来创建线程,并通过调用start()方法启动
2023-09-21

java守护线程怎么应用

Java守护线程是指在后台提供一种通用服务的线程,并且在所有非守护线程结束时自动退出。守护线程通常用于执行一些背景任务,如垃圾回收、内存管理等,以保证程序的正常运行。要创建守护线程,可以通过Thread类的setDaemon()方法来设置
2023-10-27

QT线程池的使用(QThreadPool类和QRunnable类)

本文主要介绍了QT线程池的使用(QThreadPool类和QRunnable类),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-05-17

QT中的部件怎么使用

这篇文章主要介绍“QT中的部件怎么使用”,在日常操作中,相信很多人在QT中的部件怎么使用问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”QT中的部件怎么使用”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!【1
2023-07-02

qt中radiobutton怎么使用

在qt中使用radiobutton,可以按照以下步骤进行操作:1. 首先,在Qt设计器中将一个QRadioButton控件拖放到窗口中。2. 在属性编辑器中为QRadioButton设置文本,以便用户能够看到选项的描述。3. 为QRadio
2023-09-16

C/C++ Qt QThread线程组件的具体使用是怎样的

这期内容当中小编将会给大家带来有关C/C++ Qt QThread线程组件的具体使用是怎样的,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。QThread库是QT中提供的跨平台多线程实现方案,使用时需要继承
2023-06-21

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录