首页 > 其他分享 >Qt 线程同步 QMutex、QReadWriteLock、QWaitCondition

Qt 线程同步 QMutex、QReadWriteLock、QWaitCondition

时间:2024-01-30 13:57:11浏览次数:26  
标签:Qt thread buffer QReadWriteLock start locker 线程 read QMutex

在Qt中,线程同步可以使用以下几种方式来实现:

一、互斥锁(QMutex)

互斥锁用于保护共享资源,确保在同一时间只有一个线程能够访问该资源。线程在访问共享资源之前需要获取互斥锁,使用完后再释放互斥锁,以确保同一时间只有一个线程在执行关键代码段。

1.创建QMutex对象:在需要进行线程同步的地方,首先创建一个QMutex对象。

QMutex mutex;

2.获取互斥锁:在访问共享资源之前,线程需要获取互斥锁。使用lock()方法获取互斥锁。如果互斥锁已被其他线程占用,当前线程会被阻塞,直到互斥锁被释放。

mutex.lock();

3.访问共享资源:获取到互斥锁后,线程可以安全地访问共享资源。

// 访问共享资源的代码

4.释放互斥锁:在线程完成对共享资源的访问之后,需要释放互斥锁,以便其他线程可以获取到互斥锁进行访问

mutex.unlock();

完整示例如下:

数据写入线程:

 1 class WriteThread : public QObject
 2 {
 3     Q_OBJECT
 4 public:
 5     explicit WriteThread(QQueue<int> *buffer, QMutex *locker);
 6 
 7 public slots:
 8     void on_start_write_thread();
 9 
10 private:
11     QQueue<int> *m_buffer;
12     QMutex *m_locker;
13 };
 1 WriteThread::WriteThread(QQueue<int> *buffer, QMutex *locker):m_buffer(buffer),m_locker(locker)
 2 {
 3 
 4 }
 5 
 6 void WriteThread::on_start_write_thread()
 7 {    int num = 1;
 8     while (true) {
 9         QThread::msleep(2000);
10 
11         m_locker->lock();
12         m_buffer->enqueue(num++);
13         m_locker->unlock();
14     }
15 }

数据读取线程:

 1 class ReadThread : public QObject
 2 {
 3     Q_OBJECT
 4 public:
 5     explicit ReadThread(QQueue<int> *buffer, QMutex *locker);
 6 
 7 public slots:
 8     void on_start_read_thread();
 9 
10 private:
11     QQueue<int> *m_buffer;
12     QMutex *m_locker;
13 };
 1 ReadThread::ReadThread(QQueue<int> *buffer, QMutex *locker):m_buffer(buffer),m_locker(locker)
 2 {
 3 
 4 }
 5 
 6 void ReadThread::on_start_read_thread()
 7 {
 8    while (true) {
 9     if (m_buffer->isEmpty) {
10       continue;
11     }
12     m_locker->lock();
13     int num = m_buffer->dequeue();
14     qDebug() << num;
15     m_locker->unlock();
16   }
17 
18 }

线程执行:

 1 MainWindow::MainWindow(QObject *parent) : QObject(parent)
 2 {
 3     m_write_thread = new WriteThread(&m_buffer, &m_locker);
 4     m_move_write = new QThread(this);
 5     m_write_thread->moveToThread(m_move_write);
 6     connect(this, &MainWindow::start_write_thread, m_write_thread, &WriteThread::on_start_write_thread);
 7 
 8     m_read_thread = new ReadThread(&m_buffer, &m_locker);
 9     m_move_read = new QThread(this);
10     m_read_thread->moveToThread(m_move_read);
11     connect(this, &MainWindow::start_read_thread, m_read_thread, &ReadThread::on_start_read_thread);
12 }
13 
14 void MainWindow::start_thread()
15 {
16     m_move_write->start();
17     emit start_write_thread();
18 
19     m_move_read->start();
20     emit start_read_thread();
21 }

二、QReadWriteLock(读写锁)

读写锁是Qt中用于实现读写线程同步的一种机制。它提供了一种更高效的方式来管理对共享资源的读写操作,允许多个线程同时进行读操作,但只允许一个线程进行写操作。

QReadWriteLock的使用步骤如下:

1.创建QReadWriteLock对象:在需要进行读写线程同步的地方,首先创建一个QReadWriteLock对象。

QReadWriteLock rwLock;

2.获取读锁:当线程需要进行读操作时,使用lockForRead()方法获取读锁。多个线程可以同时获取读锁,以进行并发的读操作。

rwLock.lockForRead();

3.进行读操作:获取到读锁后,线程可以安全地进行读操作,访问共享资源

// 进行读操作的代码

4.释放读锁:在读操作完成后,使用unlock()方法释放读锁,允许其他线程获取读锁。

rwLock.unlock();

5.获取写锁:当线程需要进行写操作时,使用lockForWrite()方法获取写锁。写锁是独占的,只允许一个线程获取写锁进行写操作,其他线程需要等待写锁的释放。

rwLock.lockForWrite();

6.进行写操作:获取到写锁后,线程可以安全地进行写操作,修改共享资源。

// 进行写操作的代码

7.释放写锁:在写操作完成后,使用unlock()方法释放写锁,允许其他线程获取读锁或写锁。

rwLock.unlock();

完成示例如下:

将互斥锁换成读写锁即可

 1 void WriteThread::on_start_write_thread()
 2 {
 3     int num = 1;
 4     while (true) {
 5         QThread::msleep(2000);
 6 
 7         m_locker->lockForWrite();
 8         m_buffer->enqueue(num++);
 9         m_locker->unlock();
10     }
11 }
 1 void ReadThread::on_start_read_thread()
 2 {
 3     while (true) {
 4         if (m_buffer->isEmpty()) {
 5             continue;
 6         }
 7 
 8         m_locker->lockForRead();
 9         int num = m_buffer->dequeue();
10         qDebug() << num;
11         m_locker->unlock();
12     }
13 }

 三、QWaitCondition(等待条件)

QWaitCondition是Qt中用于线程同步的一种机制,它允许线程等待特定条件的发生,并在条件满足时被唤醒继续执行。QWaitCondition通常与QMutex一起使用,以提供更复杂的线程同步机制。

QWaitCondition的使用步骤如下:

1.创建QWaitCondition对象:在需要进行线程同步的地方,首先创建一个QWaitCondition对象。

QWaitCondition condition;

2.创建QMutex对象:为了保护条件的读写操作,创建一个QMutex对象。

QMutex mutex;

3.在等待条件的线程中等待:在线程需要等待特定条件的发生时,使用wait()方法使线程进入等待状态。

1 mutex.lock();
2 condition.wait(&mutex);
3 mutex.unlock();

在调用wait()方法之前,需要先获取到互斥锁(QMutex)。这样可以确保线程在等待之前能够安全地访问和检查条件。

4.在其他线程中满足条件并唤醒等待线程:当某个条件满足时,通过wakeOne()wakeAll()方法唤醒等待的线程。

1 mutex.lock();
2 condition.wakeOne(); // 或者使用 condition.wakeAll();
3 mutex.unlock();

完整示例如下:

 1 ReadThread::ReadThread(QQueue<int> *buffer, QMutex *locker, QWaitCondition *wait_condition)
 2             :m_buffer(buffer),m_locker(locker),m_wait_condition(wait_condition)
 3 {
 4 
 5 }
 6 
 7 void ReadThread::on_start_read_thread()
 8 {
 9     while (true) {
10         m_locker->lock();
11         //线程进入等待状态。
12         m_wait_condition->wait(m_locker);
13         //满足等待条件,继续执行
14         int num = m_buffer->dequeue();
15         qDebug() << num;
16         m_locker->unlock();
17     }
18 }
 1 WriteThread::WriteThread(QQueue<int> *buffer, QMutex *locker, QWaitCondition *wait_condition)
 2             :m_buffer(buffer),m_locker(locker),m_wait_condition(wait_condition)
 3 {
 4 
 5 }
 6 
 7 void WriteThread::on_start_write_thread()
 8 {
 9     int num = 1;
10     while (true) {
11         QThread::msleep(2000);
12 
13         m_locker->lock();
14         m_buffer->enqueue(num++);
15         // 满足条件,唤醒等待线程
16         m_wait_condition->wakeOne(); // 或者使用 condition.wakeAll();
17         m_locker->unlock();
18     }
19 }
 1 MainWindow::MainWindow(QObject *parent) : QObject(parent)
 2 {
 3     m_write_thread = new WriteThread(&m_buffer, &m_locker, &m_wait_condition);
 4     m_move_write = new QThread(this);
 5     m_write_thread->moveToThread(m_move_write);
 6     connect(this, &MainWindow::start_write_thread, m_write_thread, &WriteThread::on_start_write_thread);
 7 
 8     m_read_thread = new ReadThread(&m_buffer, &m_locker, &m_wait_condition);
 9     m_move_read = new QThread(this);
10     m_read_thread->moveToThread(m_move_read);
11     connect(this, &MainWindow::start_read_thread, m_read_thread, &ReadThread::on_start_read_thread);
12 }
13 
14 void MainWindow::start_thread()
15 {
16     m_move_write->start();
17     emit start_write_thread();
18 
19     m_move_read->start();
20     emit start_read_thread();
21 }

 

标签:Qt,thread,buffer,QReadWriteLock,start,locker,线程,read,QMutex
From: https://www.cnblogs.com/ybqjymy/p/17996935

相关文章

  • Qt QQueue 详解:从底层原理到高级用法
    引言:QQueue的重要性与简介在现代软件开发中,数据结构和算法扮演着至关重要的角色。它们为程序员提供了处理各种不同场景下数据的有效方法。QQueue(队列)是一种常见且实用的数据结构,它在许多应用中都发挥着关键作用。本文将简要介绍QQueue的重要性和简介。队列(Queue)是一种遵......
  • [Qt-ColorEditor] Qt颜色编辑器,QColorDialog的优化版,支持RGB和HSV等多种方式选色
    外观分享一下我实现的颜色编辑器,主要原因是Qt的QColorDialog功能较少没法满足需求,目前已经在zeno中使用了,由于zeno有自己的样式表,所以在zeno里长这样:如果不加样式表的话长这样:功能srgb切换颜色轮选色颜色文字选色颜色滑动条选色,RGB和HSV上一个/当前颜色切换,这个主要......
  • 小项目:使用MQTT上传温湿度到Onenet服务器
    前言我们之前分别编写了DHT11、ESP8266和MQTT的代码,现在我们将它们仨整合在一起,来做一个温湿度检测小项目。这个项目可以实时地将DHT11传感器获取到的温湿度数据上传到OneNET平台。通过登录OneNET,我们随时随地可以查看温湿度数据。这种环境监测项目的应用场景有很多,其中......
  • 【Qt】Qt-文本文件读写
     读取文本文件(编码UTF8)QStringfilename="";QFilefile(filename);if(!file.open(QIODevice::Text|QIODevice::ReadOnly)){  log("Openfilefailed!");  return;}QTextStreamin(&file);in.setCodec("UTF-8");QStringline=in.re......
  • C++ Qt开发:运用QJSON模块解析数据
    Qt是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QJson组件的实现对JSON文本的灵活解析功能。JSON(JavaScriptObjectNotation)是一种轻量级......
  • Qt QtConcurrent::run()函数的两种写法
    第一种,使用lambda表达式1QFuture<void>future=QtConcurrent::run([=](){2//Codeinthisblockwillruninanotherthread3});4...第二种,使用成员函数调用QByteArray的成员函数split()1//call'QList<QByteArray>QByteArray::split(charsep)c......
  • QT Creator12.0.1运行普通C/C++程序时候没有控制台输出
    问题:QTCreator12.0.1运行普通C/C++程序时候没有控制台输出菜单栏选择:[编辑]->[设置],按下图依次设置。启用终端输出,还有去掉内部终端输出的选项运行后控制台窗口正常弹出......
  • Qt/C++音视频开发64-共享解码线程/重复利用解码/极低CPU占用/画面同步/进度同步
    一、前言共享解码线程主要是为了降低CPU占用,重复利用解码,毕竟在一个监控系统中,很可能打开了同一个地址,需要在多个不同的窗口中播放,形成多屏渲染的效果,做到真正的完全的画面同步,在主解码线程中切换了播放进度,所有关联的同一个解码线程的播放窗体也会立即同步画面,使得感官上看起来......
  • Qt 深度解析QMap与QHash
    一、QMap深度解析1、QMap是一个以升序键顺序存储键值对的数据结构(1)QMap原型为classQMap<K,T>模板(2)、QMap中的键值对根据key进行了排序(3)、QMap中的key类型必须重载operator<(小于操作符)2、QMap使用实例一 3、QMap使用实例二4、QMap的注意事项(1)、通过key获取Value时......
  • CLion搭建Qt开发环境,并解决目录重构问题(最新版)
    序言Qt版本不断更新,QtCreator也不断更新。在Qt4和Qt5时代,我一直认为开发Qt最好的IDE就是自带的QtCreator,可是时至今日,到了Qt6时代,QtCreator已经都12.0.1版本了,不仅没变的更好用,反而变得更难用了。一方面可能是我被JetBrains全家桶和各种AI代码提示插件给惯坏了,另一方面也可能是开......