Qt多线程通信(qt 多线程)
wxin55 2024-10-30 04:35 9 浏览 0 评论
目录
- 1 QSemaphore
- 2 QMutexLocker
- 3 QReadWriteLock
- 4 QFuture和QFutureWatcher
- 5 QWaitCondition
- 6 QSharedMemory
- 7 Windows CreateEvent
1 QSemaphore
QSemaphore提供了一种计数信号量机制,可以用于控制对共享资源的访问。
#include <QCoreApplication>
#include <QThread>
#include <QSemaphore>
#include <QDebug>
class Producer : public QThread
{
public:
Producer(QSemaphore *freeBytes, QSemaphore *usedBytes)
: m_freeBytes(freeBytes), m_usedBytes(usedBytes) {}
void run() override {
for (int i = 0; i < 10; ++i) {
m_freeBytes->acquire(); // 获取free区域大小
qDebug() << objectName() << "Producer produced data";
m_usedBytes->release(); // 更新Used区域大小
sleep(1); // 模拟耗时操作
}
}
private:
QSemaphore *m_freeBytes;
QSemaphore *m_usedBytes;
};
class Consumer : public QThread
{
public:
Consumer(QSemaphore *freeBytes, QSemaphore *usedBytes)
: m_freeBytes(freeBytes), m_usedBytes(usedBytes) {}
void run() override {
for (int i = 0; i < 10; ++i) {
m_usedBytes->acquire(); // 获取Used区域大小
qDebug() << objectName() << "Consumer consumed data";
m_freeBytes->release(); // 更新Free区域大小
sleep(1); // 模拟耗时操作
}
}
private:
QSemaphore *m_freeBytes;
QSemaphore *m_usedBytes;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QSemaphore freeBytes(10); // 初始化Free区域大小为10
QSemaphore usedBytes(0); // 初始化Used区域大小为0
Producer producer(&freeBytes, &usedBytes);
Producer producer1(&freeBytes, &usedBytes);
Consumer consumer(&freeBytes, &usedBytes);
Consumer consumer1(&freeBytes, &usedBytes);
Consumer consumer2(&freeBytes, &usedBytes);
producer.setObjectName("producer");
producer1.setObjectName("producer1");
consumer.setObjectName("consumer");
consumer1.setObjectName("consumer1");
consumer2.setObjectName("consumer2");
producer.start();
producer1.start();
consumer.start();
consumer1.start();
consumer2.start();
producer.wait();
producer1.wait();
consumer.wait();
consumer1.wait();
consumer2.wait();
return a.exec();
}
创建了一个生产者和一个消费者线程。生产者线程负责生成数据,消费者线程负责消费数据。通过使用QSemaphore来控制对共享资源的访问,确保生产者和消费者线程能够正确地同步执行。生产者线程在每次生成数据之前,会先获取freeBytes信号量,表示可用的Free区域大小;然后释放usedBytes信号量,表示已使用的Used区域大小。消费者线程在每次消费数据之前,会先获取usedBytes信号量,表示已使用的Used区域大小;然后释放freeBytes信号量,表示可用的Free区域大小。通过这种方式,我们实现了多线程之间的同步和通信。
2 QMutexLocker
#include <QCoreApplication>
#include <QMutex>
#include <QMutexLocker>
#include <QDebug>
#include <QThread>
class SharedResource
{
public:
void accessResource() {
QMutexLocker locker(&mutex);
// 访问共享资源
qDebug() << "Accessing shared resource"<<--a;
}
int a;
private:
QMutex mutex; // 互斥锁
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
SharedResource resource;
resource.a = 10;
// 多个线程访问共享资源
QThread thread1, thread2;
QObject::connect(&thread1, &QThread::started, [&](){ resource.accessResource(); });
QObject::connect(&thread2, &QThread::started, [&](){ resource.accessResource(); });
thread1.start();
thread2.start();
thread1.wait();
thread2.wait();
return a.exec();
}
定义了一个SharedResource类,它包含一个访问共享资源的成员函数accessResource。为了保护对共享资源的访问,我们在函数内部使用了QMutexLocker。QMutexLocker是一个RAII(Resource Acquisition Is Initialization)风格的锁管理类,它会在构造函数中自动获取互斥锁,并在析构函数中自动释放互斥锁。通过使用QMutexLocker,我们可以确保在访问共享资源时不会被其他线程打断,从而实现了线程安全的访问。在示例中,我们创建了两个线程,它们都调用了accessResource函数来访问共享资源。由于使用了QMutexLocker,这些访问操作是线程安全的,不会发生冲突或竞态条件。
3 QReadWriteLock
#include <QCoreApplication>
#include <QReadWriteLock>
#include <QDebug>
#include <QThread>
class SharedResource
{
public:
void readResource() {
QReadLocker locker(&readWriteLock);
// 读取共享资源
qDebug() << "Reading shared resource";
}
void writeResource() {
QWriteLocker locker(&readWriteLock);
// 写入共享资源
qDebug() << "Writing shared resource";
}
private:
QReadWriteLock readWriteLock; // 读写锁
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
SharedResource resource;
// 多个线程同时读取共享资源
QThread thread1, thread2,thread3,thread4,thread5;
QObject::connect(&thread1, &QThread::started, [&](){ resource.readResource(); });
QObject::connect(&thread2, &QThread::started, [&](){ resource.readResource(); });
qDebug() << "================";
// 多个线程同时写入共享资源,并有一个线程同时读取资源
QObject::connect(&thread4, &QThread::started, [&](){ resource.writeResource(); });
QObject::connect(&thread5, &QThread::started, [&](){ resource.readResource(); });
QObject::connect(&thread3, &QThread::started, [&](){ resource.writeResource(); });
thread4.start();
thread5.start();
thread3.start();
thread1.start();
thread2.start();
thread1.wait();
thread2.wait();
thread4.wait();
thread5.wait();
thread3.wait();
return a.exec();
}
定义了一个SharedResource类,它包含两个方法:readResource和writeResource。这两个方法分别用于读取和写入共享资源。为了保护对共享资源的访问,我们在方法内部使用了QReadLocker和QWriteLocker。QReadLocker用于读取时加读锁,允许多个线程同时读取共享资源,但只允许一个线程写入资源。QWriteLocker用于写入时加写锁,只允许一个线程读取或写入资源。通过使用QReadWriteLock,我们可以确保在访问共享资源时不会被其他线程打断,从而实现了线程安全的访问。在示例中,我们创建了三个线程,其中两个线程同时读取共享资源,一个线程同时写入共享资源。由于使用了QReadWriteLock,这些访问操作是线程安全的,不会发生冲突或竞态条件。
【文章福利】:Qt开发学习资料包、Qt面试题文档、项目视频、学习路线,包括(Qt C++基础,数据库编程,Qt项目实战、Qt框架、QML、Opencv、qt线程等等),免費分享,有需要的可以加君羊领取哦!~学习交流君羊937552610点击加入领取资料
4 QFuture和QFutureWatcher
#include <QCoreApplication>
#include <QtConcurrent/QFuture>
#include <QDebug>
int compute() {
// 模拟耗时操作
QThread::sleep(2);
return 42;
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
QFuture<int> future = QtConcurrent::run(compute); // 创建并开始异步任务
int value = future.result(); // 获取异步任务的结果,如果任务未完成则阻塞等待
qDebug() << "Result:" << value;
return a.exec();
}
QFuture是一个Qt类,用于表示异步计算的结果。它通常与Qt Concurrent框架一起使用,以便在后台线程中执行任务并获取结果。
QFuture的主要特点是提供了对异步操作结果的访问和监视。通过QFuture,你可以等待计算完成并获取计算结果,而无需阻塞主线程。
QFuture类提供了许多有用的方法来处理异步操作的结果,包括:
result():获取异步计算的结果。如果计算尚未完成,该方法将阻塞等待直到结果可用。
resultAt():获取指定索引处的结果。如果索引超出了结果范围的界限,该方法将返回默认值或抛出异常。
results():返回所有连续结果的列表。这在处理多个结果时很有用,例如使用Qt Concurrent的mapReduce函数时。
isResultReadyAt():检查指定索引处的结果是否已准备就绪。这可以用于避免不必要的阻塞等待。
isFinished():检查异步操作是否已完成。如果操作已完成,你可以安全地获取结果。
cancel():取消异步操作。如果操作已经开始,该方法可能无法立即停止操作,但可以尝试取消它。
pause()和resume():暂停和恢复异步操作。这对于需要暂停和恢复长时间运行的任务很有用。
QFuture还提供了一个迭代器接口,允许你使用Java风格的迭代器或STL风格的迭代器来遍历结果。这对于处理多个结果的情况非常有用,可以方便地遍历和访问结果数据。
总的来说,QFuture是一个强大的类,提供了对异步操作结果的访问和监视功能。通过使用QFuture,你可以更好地管理异步操作的流程和状态,并避免阻塞主线程,从而提高程序的性能和响应性。
QFutureWatcher是Qt框架中一个非常有用的类,用于监视异步任务的执行状态并获取任务的结果。它提供了一种方便的方式来处理在后台执行的任务,并在任务完成后进行相应的处理。
QFutureWatcher的主要作用是监视一个异步任务的执行状态。它可以告诉我们任务是否已经完成,以及任务的执行进度。当任务完成后,我们可以获取任务的结果并进行相应的处理,例如更新UI界面或执行其他操作。
QFutureWatcher提供了一种事件驱动的方式来监视和处理异步操作的结果。它通过发出信号来通知我们有关异步任务的状态更改和结果就绪的情况。我们可以连接QFutureWatcher的信号到自定义槽函数,以便在适当的时候执行特定的操作。
QFutureWatcher提供了以下重要的信号:
started():当异步任务开始执行时发出此信号。
finished():当异步任务完成时发出此信号。
resultReadyAt():当指定索引处的结果就绪时发出此信号。
resultsReadyAt():当结果集合中指定索引范围的结果就绪时发出此信号。
progressRangeChanged()、progressValueChanged()和progressTextChanged():这些信号分别在任务的最大和最小进度值更改、进度值更改或进度文本更改时发出。
此外,QFutureWatcher还提供了一些有用的槽函数,用于控制异步操作的执行和结果处理,包括:
cancel():取消异步操作。
setPaused()、pause()、resume()和togglePaused():控制异步操作的暂停和恢复。
总的来说,QFutureWatcher是一个功能强大的类,允许我们方便地监视和处理异步任务的结果。通过连接适当的信号和槽函数,我们可以灵活地处理异步操作的状态和结果,从而提高程序的响应性和性能。
5 QWaitCondition
#include <QCoreApplication>
#include <QMutex>
#include <QWaitCondition>
#include <QDebug>
#include <QThread>
class MyObject {
public:
MyObject() {
}
void sendData() {
// 锁定互斥量
QMutexLocker locker(&m_mutex);
// 模拟发送数据
qDebug() << "Sending data...";
QThread::sleep(2); // 模拟耗时操作
// 唤醒等待的线程
m_condition.wakeAll();
}
void waitForData() {
// 锁定互斥量
QMutexLocker locker(&m_mutex);
// 等待数据发送完成
while (!m_dataReceived) {
m_condition.wait(&m_mutex);
m_dataReceived = true;
}
// 数据已接收,继续执行其他操作
qDebug() << "Data received!";
}
private:
QMutex m_mutex;
QWaitCondition m_condition;
bool m_dataReceived = false; // 标记数据是否已接收
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyObject obj;
// 启动主线程和通信线程
QThread *th1 = QThread::create([&obj]() { obj.waitForData(); });
QThread *th2 = QThread::create([&obj]() { obj.sendData(); });
th1->start();
th2->start();
th1->wait();
th2->wait();
return a.exec();
}
创建了一个MyObject类,它包含一个QWaitCondition对象和一个QMutex对象。sendData()函数模拟了数据发送的过程,并使用QWaitCondition的wakeOne()方法唤醒等待的线程。waitForData()函数则使用QWaitCondition的wait()方法等待数据发送完成。在主函数中,我们创建了两个线程,一个执行waitForData()函数,另一个执行sendData()函数,从而实现多线程的同步。
6 QSharedMemory
#include <QCoreApplication>
#include <QSharedMemory>
#include <QDebug>
#include <QSharedMemory>
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// 创建共享内存对象
QSharedMemory sharedMemory("MySharedMemory");
// 尝试获取已存在的共享内存
if (sharedMemory.attach()) {
// 连接到信号槽,用于处理内存映射文件的更改
// 写入数据到共享内存
QByteArray data("Hello, shared memory!");
sharedMemory.lock();
memcpy(sharedMemory.data(), data.data(), data.size());
sharedMemory.unlock();
} else {
// 如果共享内存不存在,则创建新的共享内存并附加到当前进程
if (sharedMemory.create(1024)) {
qDebug() << "Created shared memory segment";
QByteArray data("Hello, shared memory!");
sharedMemory.lock();
memcpy(sharedMemory.data(), data.data(), data.size());
sharedMemory.unlock();
sharedMemory.lock();
QByteArray readData((char*)sharedMemory.constData(), sharedMemory.size());
qDebug() << "读取到的数据:" << readData;
sharedMemory.unlock();
sharedMemory.detach();
} else {
qDebug() << "Failed to create shared memory segment";
}
}
return a.exec();
}
创建了一个QSharedMemory对象,并尝试附加到一个已存在的共享内存段。如果共享内存段不存在,我们创建一个新的共享内存段并将其附加到当前进程。最后,我们启动应用程序并等待用户交互。
7 Windows CreateEvent
hTxEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ResetEvent(hTxEvent);
SetEvent(hTxEvent);
WaitForSingleObject(hRxEvent,WaitTime);
还可以使用Windows 中的上述函数进行线程通信
相关推荐
- ES6中 Promise的使用场景?(es6promise用法例子)
-
一、介绍Promise,译为承诺,是异步编程的一种解决方案,比传统的解决方案(回调函数)更加合理和更加强大在以往我们如果处理多层异步操作,我们往往会像下面那样编写我们的代码doSomething(f...
- JavaScript 对 Promise 并发的处理方法
-
Promise对象代表一个未来的值,它有三种状态:pending待定,这是Promise的初始状态,它可能成功,也可能失败,前途未卜fulfilled已完成,这是一种成功的状态,此时可以获取...
- Promise的九大方法(promise的实例方法)
-
1、promise.resolv静态方法Promise.resolve(value)可以认为是newPromise方法的语法糖,比如Promise.resolve(42)可以认为是以下代码的语...
- 360前端一面~面试题解析(360前端开发面试题)
-
1.组件库按需加载怎么做的,具体打包配了什么-按需加载实现:借助打包工具(如Webpack的require.context或ES模块动态导入),在使用组件时才引入对应的代码。例如在V...
- 前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?
-
Promise的finally方法是一个非常有用的工具,它无论Promise是成功(fulfilled)还是失败(rejected)都会执行,且不改变Promise的最终结果。它的实现原...
- 最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式
-
看了全网手写Promise的,大部分对于新手还是比较难理解的,其中几个比较难的点:状态还未改变时通过发布订阅模式去收集事件实例化的时候通过调用构造函数里传出来的方法去修改类里面的状态,这个叫Re...
- 前端分享-Promise可以中途取消啦(promise可以取消吗)
-
传统Promise就像一台需要手动组装的设备,每次使用都要重新接线。而Promise.withResolvers的出现,相当于给开发者发了一个智能遥控器,可以随时随地控制异步操作。它解决了三大...
- 手写 Promise(手写输入法 中文)
-
前言都2020年了,Promise大家肯定都在用了,但是估计很多人对其原理还是一知半解,今天就让我们一起实现一个符合PromiseA+规范的Promise。附PromiseA+规范地址...
- 什么是 Promise.allSettled()!新手老手都要会?
-
Promise.allSettled()方法返回一个在所有给定的promise都已经fulfilled或rejected后的promise,并带有一个对象数组,每个对象表示对应的pr...
- 前端面试-关于Promise解析与高频面试题示范
-
Promise是啥,直接上图:Promise就是处理异步函数的API,它可以包裹一个异步函数,在异步函数完成时抛出完成状态,让代码结束远古时无限回掉的窘境。配合async/await语法糖,可...
- 宇宙厂:为什么前端离不开 Promise.withResolvers() ?
-
大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发。1.为什么需要Promise.with...
- Promise 新增了一个超实用的 API!
-
在JavaScript的世界里,Promise一直是处理异步操作的神器。而现在,随着ES2025的发布,Promise又迎来了一个超实用的新成员——Promise.try()!这个新方法简...
- 一次搞懂 Promise 异步处理(promise 异步顺序执行)
-
PromisePromise就像这个词的表面意识一样,表示一种承诺、许诺,会在后面给出一个结果,成功或者失败。现在已经成为了主流的异步编程的操作方式,写进了标准里面。状态Promise有且仅有...
- Promise 核心机制详解(promise机制的实现原理)
-
一、Promise的核心状态机Promise本质上是一个状态机,其行为由内部状态严格管控。每个Promise实例在创建时处于Pending(等待)状态,此时异步操作尚未完成。当异步操作成功...
- javascript——Promise(js实现promise)
-
1.PromiseES6开始支持,Promise对象用于一个异步操作的最终完成(包括成功和失败)及结果值的表示。简单说就是处理异步请求的。之所以叫Promise,就是我承诺,如果成功则怎么处理,失败怎...
你 发表评论:
欢迎- 一周热门
- 最近发表
-
- ES6中 Promise的使用场景?(es6promise用法例子)
- JavaScript 对 Promise 并发的处理方法
- Promise的九大方法(promise的实例方法)
- 360前端一面~面试题解析(360前端开发面试题)
- 前端面试-Promise 的 finally 怎么实现的?如何在工作中使用?
- 最简单手写Promise,30行代码理解Promise核心原理和发布订阅模式
- 前端分享-Promise可以中途取消啦(promise可以取消吗)
- 手写 Promise(手写输入法 中文)
- 什么是 Promise.allSettled()!新手老手都要会?
- 前端面试-关于Promise解析与高频面试题示范
- 标签列表
-
- hive行转列函数 (63)
- sourcemap文件是什么 (54)
- display none 隐藏后怎么显示 (56)
- 共享锁和排他锁的区别 (51)
- httpservletrequest 获取参数 (64)
- jstl包 (64)
- qsharedmemory (50)
- watch computed (53)
- java中switch (68)
- date.now (55)
- git-bash (56)
- 盒子垂直居中 (68)
- npm是什么命令 (62)
- python中+=代表什么 (70)
- fsimage (51)
- nginx break (61)
- mysql分区表的优缺点 (53)
- centos7切换到图形界面 (55)
- 前端深拷贝 (62)
- kmp模式匹配算法 (57)
- jsjson字符串转json对象 (53)
- jdbc connection (61)
- javascript字符串转换为数字 (54)
- mybatis 使用 (73)
- 安装mysql数据库 (55)