Qt线程QThread详解

article/2025/10/16 8:12:09

目录

      • 前言
      • 1.QThread介绍
      • 2.QThread示例一
      • 3.QThread示例二
      • 4.线程同步

前言

在这里插入图片描述
在程序中使用线程可以提高程序的性能、并发性、响应性和稳定性,使得程序设计更加灵活和简单。但是,线程编程也有一些挑战,如线程安全性和死锁等问题需要格外注意。我们使用QT框架编程时,可以用框架提供的线程类QThread来管理线程。本文将介绍使用QThread编程时的两种方式,并给出一个数据同步的示例。

1.QThread介绍

在介绍QThread之前先复习下线程的定义,线程是操作系统中的基本执行单元,是一个独立的执行路径。每个线程都有自己的栈空间,用于存储本地变量和函数调用的上下文。多个线程可以在同一进程中并发执行,从而实现并发处理,提高程序的性能和响应能力。
与进程不同的是,线程是轻量级的,它们共享同一进程的地址空间,这意味着它们可以访问相同的内存和文件资源,从而更容易地共享数据和通信。
QThread是Qt框架中用于创建和管理线程的类。可以用QThread轻松地创建新的线程并将任务分配给它们还可以创建自己的线程类并从QThread继承,也可以使用QThread的静态函数创建线程。

QThread的主要优点是简单易用,能轻松地创建和管理线程。它提供了一些方法来控制线程的生命周期,包括start()和quit()方法来启动和停止线程,以及wait()方法来等待线程完成。

QThread还提供了一些信号来管理线程。例如,finished()信号在线程完成执行后发出,error()信号在线程发生错误时发出。

2.QThread示例一

在这个示例中有两个自定义线程:IncrementThread和DoubleThread,它们分别用于增加数字和将数字乘以2。这些线程都使用QThread类,并且都包含一个信号,以便在线程运行时向主线程发送结果。

#include <QObject>
#include <QThread>
#include <QVector>class IncrementThread : public QThread {Q_OBJECTpublic:IncrementThread(int count) : count(count) {}signals:void countChanged(int count);protected:void run() {for (int i = 1; i <= count; ++i) {emit countChanged(i);msleep(1000);}}private:int count;
};class DoubleThread : public QThread {Q_OBJECTpublic:DoubleThread(const QVector<int>& nums) : nums(nums) {}signals:void doubled(int num);protected:void run() {for (int num : nums) {emit doubled(num * 2);msleep(1000);}}private:QVector<int> nums;
};

在MainWindow类中,我们将创建线程,并将它们的信号连接到槽函数onCountChanged和onDoubled中。每当IncrementThread发出onCountChanged信号时,onDoubled将在主线程中更新标签的文本,以显示当前进度。类似地,每当DoubleThread发出doubled信号时,onDoubled将在主线程中更新标签的文本,以显示结果。

我们在构造函数中创建这两个线程,将它们的信号连接到槽函数中,并启动线程。

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "mythread.h"
#include <QDebug>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
{ui->setupUi(this);ui->label->setText("Waiting for results...");incrementThread = new IncrementThread(5);doubleThread = new DoubleThread({1, 2, 3, 4, 5});connect(incrementThread, &IncrementThread::countChanged, this, &MainWindow::onCountChanged);connect(doubleThread, &DoubleThread::doubled, this, &MainWindow::onDoubled);incrementThread->start();doubleThread->start();
}void MainWindow::onCountChanged(int count)
{ui->label->setText(QString("Incrementing %1").arg(count));qDebug()  <<  "Incrementing " << count;
}void MainWindow::onDoubled(int num)
{ui->label->setText(QString("Doubling %1").arg(num));qDebug()  << "Doubling " << num;
}MainWindow::~MainWindow()
{delete ui;
}

下面是程序运行时控制台输出的信息,从中可以看出两个线程是交替运行的。
在这里插入图片描述

3.QThread示例二

在这个示例中,我们创建了一个Worker类,该类包含一个doWork槽函数,用于在新线程中执行任务。在main函数中,我们创建了一个新的QThread对象和一个Worker对象,并将Worker对象的doWork槽函数连接到QThread对象的started信号上。然后,我们将Worker对象通过moveThread()方法移动到新线程中,并启动新线程。在主线程中,我们也有一个类似的循环,用于展示主线程和新线程是同时执行的。在循环结束后,我们调用了quit函数,以停止新线程的事件循环,并使用wait函数等待线程完成。

#include <QCoreApplication>
#include <QThread>
#include <QDebug>
#include <chrono>class Worker : public QObject
{Q_OBJECTpublic:Worker(int num_iterations) : m_num_iterations(num_iterations) {}public slots:void doWork() {for (int i = 0; i < m_num_iterations; i++) {qDebug() << "Thread function is running...";QThread::msleep(1000);}}private:int m_num_iterations;
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);int num_iterations = 5;QThread thread;Worker worker(num_iterations);//把线程启动信号与worker的doWork槽函数绑定在一起QObject::connect(&thread, &QThread::started, &worker, &Worker::doWork);//将woker对象移动到thread线程中执行worker.moveToThread(&thread);thread.start();for (int i = 0; i < num_iterations; i++) {qDebug() << "Main thread is running...";QThread::msleep(500);}thread.quit();thread.wait();return a.exec();
}

注意,若调用moveToThread()方法将worker对象移动到某个线程,则worker不能指定parent指针。默认情况下,对象是在哪个线程创建的,就属于哪个线程。

4.线程同步

在这个示例中,我们将创建一个线程并在其中使用QWaitCondition和QMutex来实现线程同步。

#include <QThread>
#include <QWaitCondition>
#include <QMutex>
#include <QDebug>class MyThread : public QThread {
public:void run() override {//加锁QMutexLocker locker(&mutex);qDebug() << "Thread started";// Do some work hereqDebug() << "Thread waiting";//线程挂起,直到调用wakeUp函数后,继续往下执行condition.wait(&mutex);qDebug() << "Thread resumed";// Do more work hereqDebug() << "Thread finished";}void wakeUp() {QMutexLocker locker(&mutex);condition.wakeOne();}private:QWaitCondition condition;QMutex mutex;
};int main(int argc, char *argv[])
{MyThread thread;thread.start();// Do some other work herethread.wakeUp();thread.wait();return 0;
}

在这个示例中,我们创建了一个MyThread类,继承自QThread,重写了run()函数,在其中执行一些工作。在该函数中,我们获取了一个QMutexLocker对象,以确保线程同步,并输出一些信息来显示线程已启动。

然后,我们调用QWaitCondition的wait()方法,将线程挂起,直到其他线程调用了wakeUp()方法。在等待期间,我们释放了QMutexLocker,以允许其他线程对共享资源进行访问。

在wakeUp()方法中,我们获取了QMutexLocker对象,以确保线程同步,并调用QWaitCondition的wakeOne()方法,以唤醒一个挂起的线程。

在主线程中,我们创建了一个MyThread对象并调用start()方法来启动线程。然后,我们执行一些其他工作,并在最后调用wakeUp()方法来唤醒线程。最后,我们调用wait()方法等待线程完成。

这个示例演示了如何使用QWaitCondition和QMutex来实现线程同步。QWaitCondition用于等待线程唤醒,而QMutex用于保护共享资源并防止竞争条件。通过使用这些类,我们可以编写线程安全的代码,并避免死锁和竞争条件的问题。

以上就是本文的全部内容了,希望对大家有帮助,如有问题,欢迎指正!


http://chatgpt.dhexx.cn/article/85v2P1MF.shtml

相关文章

PyQT5 多线程 QThread

PyQT5 多线程 在常规的界面软件中&#xff0c;需要将UI线程和工作线程加以区分&#xff0c;主要原因是某些工作线程很复杂且耗时&#xff0c;比如下载某个文件或者长时间的计算&#xff0c;当执行这些进程时&#xff0c;UI主进程会被阻塞&#xff0c;界面会出现未响应的状态&a…

QThread之moveToThread用法

一、怎么用 使用一个QObject作为Worker&#xff0c;并moveToThread到线程上&#xff0c;那么这个QObject生存在此线程上&#xff0c;其信号会在此线程上发射&#xff0c;其槽函数在此线程上执行。 意味着什么&#xff0c;意味着多线程操作时&#xff0c;若通过信号槽方式&…

Qt 多线程编程的 QThread 类 (详细)

本文结构如下&#xff1a; 概述优雅的开始我们的多线程编程之旅 我们该把耗时代码放在哪里&#xff1f;再谈 moveToThread()启动线程前的准备工作 开多少个线程比较合适&#xff1f;设置栈大小启动线程/退出线程 启动线程优雅的退出线程操作运行中的线程 获取状态 运行状态线程…

QT之多线程(QThread)的简单使用

一、线程简述 线程&#xff08;thread&#xff09;是操作系统能够进行运算调度的最小单位。一条线程指的是进程中一个单一顺序的控制流&#xff0c;它被包含在进程之中&#xff0c;是进程中的实际运作单位。一个进程中可以并发多个线程&#xff0c;每条线程并行执行不同的任务…

Qt 之 QThread(深入理解)

作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 为了让程序尽快响应用户操作,在开发应用程序时经常会使用到线程。对于耗时操作如果不使用线程,UI界面将会长时间处于停滞状态,这种情况是用户非常不愿意看到的,我们可以用线程来解决这个问题。 前面,已…

Qt线程:QThread

一、描述 一个QThread对象管理程序内的一个线程&#xff0c;QThreads在run()中开始执行。默认情况下&#xff0c;run()通过调用exec()启动事件循环&#xff0c;并在线程内部运行一个Qt事件循环。 可以通过使用 QObject::moveToThread() 将对象移动到线程来使用它们。 class W…

PyQt中的多线程QThread示例

PyQt中的多线程 一、PyQt中的多线程二、创建线程2.1 设计ui界面2.2 设计工作线程2.3 主程序设计 三、运行结果示例 一、PyQt中的多线程 传统的图形用户界面应用程序都只有一个执行线程&#xff0c;并且一次只执行一个操作。如果用户从用户界面中调用一个比较耗时的操作&#x…

【Qt】Qt的线程(两种QThread类的详细使用方式)

Qt提供QThread类以进行多任务处理。与多任务处理一样&#xff0c;Qt提供的线程可以做到单个线程做不到的事情。例如&#xff0c;网络应用程序中&#xff0c;可以使用线程处理多种连接器。 QThread继承自QObject类&#xff0c;且提供QMutex类以实现同步。线程和进程共享全局变量…

Qt - 一文理解QThread多线程(万字剖析整理)

目录 为什么需要多线程QThread使用方法new QThread Class & Override run()new Object Class & moveToThread(new QThread) connect事件循环源码分析如何正确退出线程堆栈大小优先级线程间通讯线程同步互斥锁读写锁信号量条件变量 可重入与线程安全QObject的可重入性开…

Qt 线程中QThread的使用

文章目录 Qt 线程中QThread的使用1. 线程类 QThread1.1 常用共用成员函数1.2 信号槽1.3 静态函数1.4 任务处理函数 2. 使用方式 12.2 示例代码3. 使用方式 23.1 操作步骤3.2 示例代码 Qt 线程中QThread的使用 在进行桌面应用程序开发的时候&#xff0c; 假设应用程序在某些情况…

Qt之QThread(深入理解)

简述 为了让程序尽快响应用户操作&#xff0c;在开发应用程序时经常会使用到线程。对于耗时操作如果不使用线程&#xff0c;UI界面将会长时间处于停滞状态&#xff0c;这种情况是用户非常不愿意看到的&#xff0c;我们可以用线程来解决这个问题。 前面&#xff0c;已经介绍了…

Qt之QThread介绍(常用接口及实现、自动释放内存、关闭窗口时停止线程运行、同步互斥)

在程序设计中&#xff0c;为了不影响主程序的执行&#xff0c;常常把耗时操作放到一个单独的线程中执行。Qt对多线程操作有着完整的支持&#xff0c;Qt中通过继承QThread并重写run()方法的方式实现多线程代码的编写。针对线程之间的同步与互斥问题&#xff0c;Qt还提供了QMutex…

Qt线程QThread开启和安全退出

1、线程开启 Qt中&#xff0c;开启子线程&#xff0c;一般有两种方法&#xff1a; a, 定义工作类worker: worker继承 QThread, 重写run函数&#xff0c;在主线程中实例化worker&#xff0c;把耗时工作放进worker的run函数中完成&#xff0c;结束后&#xff0c;往主线程中发信…

QThread的用法

概述 QThread类提供了一个与平台无关的管理线程的方法。一个QThread对象管理一个线程。QThread的执行从run()函数的执行开始&#xff0c;在Qt自带的QThread类中&#xff0c;run()函数通过调用exec()函数来启动事件循环机制&#xff0c;并且在线程内部处理Qt的事件。在Qt中建立线…

Oracle 定时任务执行存储过程【建议收藏】

首先用一个完整的例子来实现定时执行存储过程。 任务目标&#xff1a;每小时向test表中插入一条数据。 实现方案&#xff1a; 1.通过 oracle 中 dbms_job 完成存储过程的定时调用 2.在存储过程中完成相应的逻辑操作 实现步骤&#xff1a; 1.创建一个测试表 create table test…

【Mysql】MySQL 用户执行存储过程的权限

问题 运行存储过程报错&#xff1a; 原因 查询资料&#xff1a; 1305错误&#xff0c;由于当前用户没用权限&#xff0c;对用户进行授权后可以执行。 解决 MySQL创建存储过程/函数需要的权限&#xff1a; alter routine---修改与删除存储过程/函数 create routine--创建…

goland 使用 gorm 执行 存储过程 : go语言 执行存储过程

使用 gorm 执行 存储过程 初安装依赖代码&#xff1a; 附存储过程图片存储过程代码&#xff08;创建&#xff09; 表结构表结构图表结构代码 初 最近遇到要写存储过程需求&#xff0c;使用 大佬写的 框架 gorm 来完成。简直是方便的不行&#xff1a; 直接上代码&#xff1a; …

JDBC之CallableStatement执行存储过程

​ 在前面的一篇文章中&#xff0c;我们学习使用Statement、PreparedStatement来完成对数据表的增删改查。而存储过程作为数据库的重要组成部分&#xff08;痛点&#xff0c;当时学的时候头发都掉了好几根&#x1f62d;&#xff09;&#xff0c;那JDBC是如何执行存储过程呢&…

mysql创建定时任务执行存储过程

存储过程已添加好&#xff1a;https://blog.csdn.net/YXWik/article/details/127283316 1.创建定时器用来执行存储过程函数 create event delete_data on schedule every 10 second do call delete_data();这里的第一行代表的创建名称为delete_data的事件 第二行是执行周期为…

Oracle 定时任务执行存储过程

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、创建存储过程一、创建定时任务 一、创建存储过程 CREATE OR REPLACE PROCEDURE TESTCREATE AS --存储过程名称I INT : 1; --变量 BEGINWHILE I < 10 LOOP -…