首页 > 其他分享 >【QT】Qt 多线程

【QT】Qt 多线程

时间:2024-08-03 10:25:31浏览次数:17  
标签:Widget include QT myThread 线程 mutex 多线程 Qt

多线程

qt 多线程

1. Qt 多线程概述

在 Qt 中,多线程的处理⼀般是通过 QThread 类来实现。QThread 代表⼀个在应用程序中可以独立控制的线程,也可以和进程中的其他线程共享数据。QThread 对象管理程序中的⼀个控制线程。

2. QThread 常用 API

在这里插入图片描述

3. 使用线程

创建线程的步骤:

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

示例代码:

1、首先新建 Qt 项目,设计 UI 界面如下,一个 labelPushButton

在这里插入图片描述

2、新建一个类,继承于 QThread 类;

在这里插入图片描述

3、timethread.h 的程序如下:

			#include <QThread>
			
			class TimeThread : public QThread
			{
			    Q_OBJECT
			public:
			    TimeThread();
			    
			    void run();     // 线程任务函数
			    
			signals:
			    void sendTime(QString Time);    // 声明信号函数
			};

4、widget.h 程序如下:

			#include <QWidget>
			#include <timethread.h>
			
			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 showTime(QString Time);
			
			    void on_pushButton_clicked();
			
			private:
			    Ui::Widget *ui;
			    TimeThread t;   // 定义线程对象
			};

5、timethread.cpp 程序如下:

			#include "timethread.h"
			#include <QTime>
			#include <QDebug>
			
			
			TimeThread::TimeThread()
			{}
			
			void TimeThread::run()
			{
			    while(1) {
			        QString time = QTime::currentTime().toString("hh:mm:ss");
			        qDebug() << time;
			        
			        emit sendTime(time);    // 发送信号
			        sleep(1);
			    }
			}
  1. widget.cpp 如下:

     			#include "widget.h"
     			#include "ui_widget.h"
     			
     			Widget::Widget(QWidget *parent)
     			    : QWidget(parent)
     			    , ui(new Ui::Widget)
     			{
     			    ui->setupUi(this);
     			    connect(&t, &TimeThread::sendTime, this, &Widget::showTime);
     			}
     			
     			Widget::~Widget()
     			{
     			    delete ui;
     			}
     			
     			void Widget::showTime(QString Time)
     			{
     			    ui->label->setText(Time);
     			}
     			
     			void Widget::on_pushButton_clicked()
     			{
     			    t.start();  // 开启线程
     			}
    

效果如下:

在这里插入图片描述

注意:

  • 线程函数内部不允许操作 UI 图形界⾯,⼀般⽤数据处理;
  • connect() 函数第五个参数表示的为连接的方式,且只有在多线程的时候才意义。

connect() 函数第五个参数为 Qt::ConnectionType,用于指定信号和槽的连接类型。同时影响信号的传递方式和槽函数的执行顺序。Qt::ConnectionType 提供了以下五种方式:

在这里插入图片描述

4. 线程安全

实现线程互斥和同步常用的类有:

  • 互斥锁:QMutex、QMutexLocker
  • 条件变量:QWaitCondition
  • 信号量:QSemaphore
  • 读写锁:QReadLocker、QWriteLocker、QReadWriteLock

(1)互斥锁

互斥锁是⼀种保护和防止多个线程同时访问同⼀对象实例的方法,在 Qt 中,互斥锁主要是通过 QMutex 类来处理。

  • QMutex

特点:QMutexQt 框架提供的互斥锁类,用于保护共享资源的访问,实现线程间的互斥操作。

用途:在多线程环境下,通过互斥锁来控制对共享数据的访问,确保线程安全。

			QMutex mutex;
			mutex.lock(); //上锁
			//访问共享资源
			//...
			mutex.unlock(); //解锁
  • QMutexLocker

特点:QMutexLockerQMutex 的辅助类,使用 RAII(Resource Acquisition Is Initialization)方式对互斥锁进⾏上锁和解锁操作。

用途:简化对互斥锁的上锁和解锁操作,避免忘记解锁导致的死锁等问题。

			QMutex mutex;
			{
			 QMutexLocker locker(&mutex); //在作⽤域内⾃动上锁
			 
			 //访问共享资源
			 //...
			} //在作⽤域结束时自动解锁
  • QReadWriteLocker、QReadLocker、QWriteLocker

特点:

QReadWriteLock 是读写锁类,用于控制读和写的并发访问。
QReadLocker 用于读操作上锁,允许多个线程同时读取共享资源。
QWriteLocker 用于写操作上锁,只允许⼀个线程写⼊共享资源。

用途:在某些情况下,多个线程可以同时读取共享数据,但只有⼀个线程能够进行写操作。读写锁提供了更高效的并发访问方式。

			QReadWriteLock rwLock;
			//在读操作中使⽤读锁
			{
			 QReadLocker locker(&rwLock); //在作⽤域内⾃动上读锁
			 
			 //读取共享资源
			 //...
			 
			} //在作⽤域结束时⾃动解读锁
			//在写操作中使⽤写锁
			{
			 QWriteLocker locker(&rwLock); //在作⽤域内⾃动上写锁
			 
			 //修改共享资源
			 //...
			 
			} //在作⽤域结束时⾃动解写锁

示例代码:

1、myThread.h 程序如下:

			#include <QThread>
			#include <QMutex>
			
			
			class myThread : public QThread
			{
			    Q_OBJECT
			public:
			    explicit myThread(QObject* parent = nullptr);
			
			    void run();
			private:
			    static QMutex mutex;    // 多个线程使用一把锁
			    static int num;         // 多个线程访问一个数据
			};

2、myThread.cpp 程序如下:

			#include "mythread.h"
			#include <QDebug>
			
			QMutex myThread::mutex;
			int myThread::num = 0;
			
			myThread::myThread(QObject* parent) : QThread(parent)
			{}
			
			void myThread::run()
			{
			    while (1) {
			        this->mutex.lock(); // 加锁
			        qDebug() << "Current Thread: " << this << ", Value: " << this->num++;
			        this->mutex.unlock(); // 解锁
			        QThread::sleep(1);  // 线程睡眠两秒
			    }
			}

3、widget.h 程序如下:

			class Widget : public QWidget
			{
			    Q_OBJECT
			
			public:
			    Widget(QWidget *parent = nullptr);
			    ~Widget();
			
			private:
			    Ui::Widget *ui;
			};

4、widget.cpp 程序如下:

			#include "widget.h"
			#include "ui_widget.h"
			#include "mythread.h"
			
			Widget::Widget(QWidget *parent)
			    : QWidget(parent)
			    , ui(new Ui::Widget)
			{
			    ui->setupUi(this);
			
			    myThread* t1 = new myThread(this);
			    myThread* t2 = new myThread(this);
			
			    t1->start();
			    t2->start();
			}

执行效果如下,两个线程使用一把锁,操作⼀个数据,数据会被两个线程依次打印:0、1、2、3、4 …

在这里插入图片描述

示例代码2: 在上述示例的基础上使用 QMutexLocker 锁,只修改 myThread.cpp 即可:

			#include "mythread.h"
			#include <QDebug>
			
			QMutex myThread::mutex;
			int myThread::num = 0;
			
			myThread::myThread(QObject* parent) : QThread(parent)
			{}
			
			void myThread::run()
			{
			    while (1) {
			    	//QMutexLocker:创建的时候加锁,当QMutexLocker局部销毁的时候解锁
			        {
			            QMutexLocker lock(&this->mutex);
			            qDebug() << "Current Thread: " << this << ", Value: " << this->num++;
			        }
			        QThread::sleep(1);
			    }
			}

(2)条件变量

在多线程编程中,假设除了等待操作系统正在执行的线程之外,某个线程还必须等待某些条件满足才能执行,这时就会出现问题。这种情况下,线程会很自然地使用锁的机制来阻塞其他线程,因为这只是线程的轮流使用,并且该线程等待某些特定条件,人们会认为需要等待条件的线程,在释放互斥锁或读写锁之后进⼊了睡眠状态,这样其他线程就可以继续运行。当条件满足时,等待条件的线程将被另⼀个线程唤醒。

在 Qt 中,专门提供了 QWaitCondition 类来解决像上述这样的问题。

特点:QWaitCondition 是 Qt 框架提供的条件变量类,用于线程之间的消息通信和同步。

用途:在某个条件满足时等待或唤醒线程,用于线程的同步和协调。

简单的伪代码用法如下:

			QMutex mutex;
			QWaitCondition condition;
			//在等待线程中
			mutex.lock();
			//检查条件是否满⾜,若不满⾜则等待
			while (!conditionFullfilled()) 
			{
			 condition.wait(&mutex); //等待条件满⾜并释放锁
			}
			//条件满⾜后继续执⾏
			//...
			mutex.unlock();
			//在改变条件的线程中
			mutex.lock();
			//改变条件
			changeCondition();
			condition.wakeAll(); //唤醒等待的线程
			mutex.unlock();

(3)信号量

有时在多线程编程中,需要确保多个线程可以相应的访问⼀个数量有限的相同资源。例如,运行程序的设备可能是非常有限的内存,因此我们更希望需要大量内存的线程将这一事实考虑在内,并根据可用的内存数量进行相关操作,多线程编程中类似问题通常用信号量来处理。信号量类似于增强的互斥锁,不仅能完成上锁和解锁操作,而且可以跟踪可用资源的数量。

特点:QSemaphore 是 Qt 框架提供的计数信号量类,用于控制同时访问共享资源的线程数量。

用途:限制并发线程数量,用于解决⼀些资源有限的问题。

			QSemaphore semaphore(2); //同时允许两个线程访问共享资源
			//在需要访问共享资源的线程中
			semaphore.acquire(); //尝试获取信号量,若已满则阻塞
			//访问共享资源
			//...
			semaphore.release(); //释放信号量
			//在另⼀个线程中进⾏类似操作

标签:Widget,include,QT,myThread,线程,mutex,多线程,Qt
From: https://blog.csdn.net/YoungMLet/article/details/140281319

相关文章

  • Qt C++ 调用 Python 之 PyObject* 数据类型转换
    整数:PyLong_FromLong和PyLong_AsLong类型检查函数:PyLong_Check()intcppInt=42;//C++整数转换为Python整数对象PyObject*pyInt=PyLong_FromLong(cppInt);//Python整数对象转换为C++整数longcppIntFromPy=PyLong_AsLong(pyInt);Py_DECREF(pyInt)......
  • QT QProcess: Destroyed while process (“apple.exe“) is still running
    一、出错原因因为我这个程序是一直运行的,它会一直回显数据,如果你使用对象,start启动这个命令后,程序认为QProcess已经执行完毕,自动回收,但是此时程序正在执行中,所以无法销毁这个进程,导致出现这个问题。二、错误代码QStringcmd="./bin/apple.exe";QStringListargs;......
  • Qt之QProcess
    一、简介QProcess是Qt框架提供的一个类,用于在应用程序中执行外部进程。它提供了一系列函数来启动、控制和与外部进程进行交互。QProcess的一些重要特性和功能包括:启动外部进程:QProcess可以用于启动外部应用程序或命令行工具。通过start函数可以指定要执行的程序路径以及相关......
  • Qt 登录界面
            本文代码效果如下:    本文代码:https://download.csdn.net/download/Sakuya__/89607657https://download.csdn.net/download/Sakuya__/89607657代码之路 LoginTitleBar.h  自定义的透明标题栏#ifndefLOGINTITLEBAR_H#defineLOGINTITLEBA......
  • Qt 和 VS 使用 crypto++
    官网:https://www.cryptopp.comGitHub:https://github.com/weidai11/cryptopp修改后的820版本https://github.com/dragonfly1208/cryptopp/tree/cryptopp820在线文档:https://www.cryptopp.com/docs/ref/index.html1生成动态库静态库文件1.1VS编译生成dll和lib库,版本:cryptop......
  • Qt项目——文本编辑器(功能模块④)
    项目地址:GitHub-Outlier9/CatEditor:Cat文本编辑器--Qt有帮助的话各位点点star啦,感谢!如果有需要学习该项目的人,觉得看文档较为困难,可以加我联系方式,给github点个star后可免费提供学习视频!!!(11)字体颜色文字设置颜色操作,在.ui界面对colorAction转到槽,选triggered信号,然......
  • 多线程编程
    目录思维导图:学习内容:1. 多线程基本概念2.多线程编程2.1 pthread_create:创建线程 2.2 pthread_self线程号的获取2.3 pthread_exit:线程退出函数课外作业:1、使用两个线程完成两个文件的拷贝,分支线程1拷贝前一半,分支线程2拷贝后一半,主线程回收两个分支线程的资......
  • x264 中多线程相关编码参数详细介绍
    多线程编码相关参数参数名称参数类型参数含义cpuuint32_tcpu型号i_threadsint并行编码线程数i_lookahead_threadsint在lookahead分析中使用多线程b_deterministicint当开启多线程时是否允许非确定性优化b_sliced_threadsint是否使用基于......
  • VSC环境配置(QT)
    VisualStudioCode1.QT安装系统:win10安装准备:官网下载qt-online-installer-windows-x64.exe在线安装程序QT账户申请个人免费版选择版本:勾选Archive并筛选选择对应组件若是自己下载MinGW,需要使用posix版本,实测5.3、7.3和8.1posix版本均可使用,为了保持一致性......
  • Log4cplus导入QT5(VSCode)
    下载GitHub地址:https://github.com/log4cplus/log4cplus版本选择log4cplus-2.0.2编译环境搭建完成后即可CMake编译生成预编译库,可参考该项目README.md进行功能选择导入在实际工程CMakeLists.txt中导入头文件(库include目录),并链接预编译好的.dll文件到项目中运行及调试la......