【QT5 多线程示例】信号量

news2025/3/29 15:52:58

信号量

【C++并发编程】(八)信号量

QT中的信号量类是QSemaphore,用法与C++标准中的std::counting_semaphore类似。不同的是, QSemaphore无法指定最大计数。为了限定最大计数,可以采用两个QSemaphore信号量。下面使用一个生成者-消费者例子展示QSemaphore的用法:

https://github.com/BinaryAI-1024/QtStudy/tree/master/thread/semaphore

// main.cpp
#include <QCoreApplication>
#include <QThread>
#include "producer.h"
#include "consumer.h"

// 定义全局变量
const int BufferSize = 5;
QSemaphore emptySlots(BufferSize); // 管理缓冲区的空闲空间
QSemaphore fullSlots(0);           // 管理缓冲区的已用空间
int buffer[BufferSize];  

int main(int argc, char *argv[]) {
    QCoreApplication a(argc, argv);

    // 创建线程
    QThread producerThread, consumerThread;

    // 创建生产者和消费者对象
    Producer producer;
    Consumer consumer;

    // 将对象移动到线程
    producer.moveToThread(&producerThread);
    consumer.moveToThread(&consumerThread);

    // 连接线程启动信号
    QObject::connect(&producerThread, &QThread::started, &producer, &Producer::produce);
    QObject::connect(&consumerThread, &QThread::started, &consumer, &Consumer::consume);

    // 启动线程
    producerThread.start();
    consumerThread.start();



    return a.exec();
}

// consumer.h
#ifndef CONSUMER_H
#define CONSUMER_H

#include <QObject>
#include <QSemaphore>

// main.cpp中的全局变量
extern QSemaphore emptySlots;
extern QSemaphore fullSlots;
extern int buffer[];
extern const int BufferSize;  // 添加 BufferSize 声明

class Consumer : public QObject {
    Q_OBJECT
public:
    explicit Consumer(QObject *parent = nullptr);

public slots:
    void consume();
};

#endif // CONSUMER_H

//consumer.cpp
#include "consumer.h"
#include <QDebug>
#include <QThread>


Consumer::Consumer(QObject *parent) : QObject(parent) {}


void Consumer::consume() {
    for (int i = 0; i < 10; ++i) {
        fullSlots.acquire();  // 等待直到有可消费的数据,如果有fullSlots计数-1
        int data = buffer[i % BufferSize];  // 现在 BufferSize 可用
        qDebug() << "Consumed:" << data << "by thread" << QThread::currentThread();
        emptySlots.release(); // 释放空槽位emptySlots计数+1
        QThread::msleep(1000);
    }
}

//producer.h
#ifndef PRODUCER_H
#define PRODUCER_H

#include <QObject>
#include <QSemaphore>

// main.cpp中的全局变量
extern QSemaphore emptySlots;
extern QSemaphore fullSlots;
extern int buffer[];
extern const int BufferSize;

class Producer : public QObject {
    Q_OBJECT
public:
    explicit Producer(QObject *parent = nullptr);

public slots:
    void produce();
};

#endif // PRODUCER_H

//producer.cpp
#include "producer.h"
#include <QDebug>
#include <QThread>


Producer::Producer(QObject *parent) : QObject(parent) {}


void Producer::produce() {
    for (int i = 0; i < 10; ++i) {
        emptySlots.acquire();  //  等待,直到缓冲区有空位,如果有emptySlots计数-1
        buffer[i % BufferSize] = i;
        qDebug() << "Produced:" << i << "by thread" << QThread::currentThread();
        fullSlots.release();   // 生产了一个数据:fullSlots计数+1
        QThread::msleep(500);
    }
}


emptySlots.acquire() 确保生产者生产的数据不会超过缓冲区大小。

fullSlots.acquire() 确保消费者不会读取空数据。

emptySlots.release()fullSlots.release() 保持生产消费的平衡。

emptySlotsfullSlots的计数有一个加一就有一个减一,保证了emptySlots计数+fullSlots计数=BuffferSize。这确保了生产者生产的数据不会超过缓冲区的大小。

结果:

Produced: 0 by thread QThread(0x77fe98)
Consumed: 0 by thread QThread(0x77fe90)
Produced: 1 by thread QThread(0x77fe98)
Produced: 2 by thread QThread(0x77fe98)
Consumed: 1 by thread QThread(0x77fe90)
Produced: 3 by thread QThread(0x77fe98)
Consumed: 2 by thread QThread(0x77fe90)
Produced: 4 by thread QThread(0x77fe98)
Produced: 5 by thread QThread(0x77fe98)
Consumed: 3 by thread QThread(0x77fe90)
Produced: 6 by thread QThread(0x77fe98)
Produced: 7 by thread QThread(0x77fe98)
Consumed: 4 by thread QThread(0x77fe90)
Produced: 8 by thread QThread(0x77fe98)
Produced: 9 by thread QThread(0x77fe98)
Consumed: 5 by thread QThread(0x77fe90)
Consumed: 6 by thread QThread(0x77fe90)
Consumed: 7 by thread QThread(0x77fe90)
Consumed: 8 by thread QThread(0x77fe90)
Consumed: 9 by thread QThread(0x77fe90)

程序中设置了消费者取走数据的速度比生产者慢,因此可以看到 buffer 被逐步填满,之后再被逐步消费的情况。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2322241.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入理解 Spring Boot 应用的生命周期:从启动到关闭的全流程解析

引言 Spring Boot 是当今 Java 开发中最流行的框架之一&#xff0c;它以简化配置和快速开发著称。然而&#xff0c;要真正掌握 Spring Boot&#xff0c;理解其应用的生命周期是至关重要的。本文将深入探讨 Spring Boot 应用的生命周期&#xff0c;从启动到关闭的各个阶段&…

【算法笔记】图论基础(一):建图、存图、树和图的遍历、拓扑排序、最小生成树

目录 何为图论图的概念 图的一些基本概念有向图和无向图带权图连通图和非连通图对于无向图对于有向图 度对于无向图对于有向图一些结论 环自环、重边、简单图、完全图自环重边简单图 稀疏图和稠密图子图、生成子图同构 图的存储直接存边邻接矩阵存边邻接表存边链式前向星存边 图…

SpringMVC 请求与响应处理详解

引言 在 Java Web 开发中&#xff0c;SpringMVC 作为 Spring 框架的重要模块&#xff0c;提供了强大的请求和响应处理机制。本文将深入探讨 SpringMVC 中请求和响应的处理方式&#xff0c;结合实际案例&#xff0c;帮助开发者更好地理解和应用这些功能。 一、SpringMVC 请求处…

【python】requests 爬虫高效获取游戏皮肤图

1. 引言 在当今的数字时代&#xff0c;游戏已经成为许多人生活中不可或缺的一部分。而游戏中的皮肤&#xff0c;作为玩家个性化表达的重要方式&#xff0c;更是受到了广泛的关注和喜爱。然而&#xff0c;对于许多玩家来说&#xff0c;获取游戏皮肤往往需要花费大量的时间和精力…

(UI自动化测试web端)第二篇:元素定位的方法_css定位之ID选择器

看代码里的【find_element_by_css_selector( )】( )里的表达式怎么写&#xff1f; 文章介绍了第一种写法id选择器&#xff0c;其实XPath元素定位要比CSS好用&#xff0c;原因是CSS无法使用下标&#xff08;工作当中也是常用的xpath&#xff09;&#xff0c;但CSS定位速度比XPat…

23种设计模式-代理(Proxy)设计模式

代理设计模式 &#x1f6a9;什么是代理设计模式&#xff1f;&#x1f6a9;代理设计模式的特点&#x1f6a9;代理设计模式的结构&#x1f6a9;代理设计模式的优缺点&#x1f6a9;代理设计模式的Java实现&#x1f6a9;代码总结&#x1f6a9;总结 &#x1f6a9;什么是代理设计模式…

【react18】react项目使用mock模拟后台接口

前后端分离项目&#xff0c;后端还没有接口的时候&#xff0c;前端可以使用mockjs的技术实行假数据的模拟。这里使用的是mock的库msw实现这个业务. MSW msw是mock的工具&#xff0c;官网地址是在这里 使用步骤 1.安装msw npm install mswlatest --save-dev2.新建存放mock接…

Windows下VSCode的安装

前言 VSCode的安装看起来平平无奇&#xff0c;但也不是轻轻松松的。笔者将最新的Windows下安装VSCode&#xff0c;以及运行最简单的C程序的过程记录下来&#xff0c;供后续的自己和大家参考。 一、官网下载安装包 Visual Studio Code - Code Editing. Redefined 二、安装 直接…

django入门教程之templates和static资源【五】

使用app01子应用举例说明模板的使用。templates官方文档。 templates完整流程认知 第一步&#xff0c;在settings.py中注册app01子应用。 第二步&#xff0c;在app01目录下&#xff0c;新建templates和static目录&#xff0c;用于存放模板文件和资源文件。目录结构如下&#…

【区块链安全 | 第一篇】密码学原理

文章目录 1.哈希函数1.1 哈希函数的性质1.2 常见哈希算法1.3 Merkle Tree&#xff08;默克尔树&#xff09;1.4 HMAC&#xff08;哈希消息认证码&#xff09; 2. 公钥密码学2.1 对称加密 vs 非对称加密2.2 RSA 算法2.3 ECC&#xff08;椭圆曲线密码学&#xff09;2.4 Diffie-He…

Linux安装MySQL数据库并使用C语言进行数据库开发

目录 一、前言 二、安装VMware运行Ubuntu 1.安装VMware 2.使用VMware打开Ubuntu 三、配置VMware使用网卡 1.添加NAT网卡 四、Linux下安装MySQL数据库 五、安装MySQL开发库 六、演示代码 sql_connect.c sql_connect.h main.c中数据库相关代码 结尾 一、前言 由于最…

2024年MathorCup数学建模A题移动通信网络中PCI规划问题解题全过程文档加程序

2024年第十四届MathorCup高校数学建模挑战赛 A题 移动通信网络中PCI规划问题 原题再现&#xff1a; 物理小区识别码(PCI)规划是移动通信网络中下行链路层上&#xff0c;对各覆盖小区编号进行合理配置&#xff0c;以避免PCI冲突、PCI混淆以及PCI模3干扰等现象。PCI规划对于减少…

Redis实战常用二、缓存的使用

一、什么是缓存 在实际开发中,系统需要"避震器"&#xff0c;防止过高的数据访问猛冲系统,导致其操作线程无法及时处理信息而瘫痪. 这在实际开发中对企业讲,对产品口碑,用户评价都是致命的。所以企业非常重视缓存技术; 缓存(Cache)&#xff1a;就是数据交换的缓冲区&…

通过国内源在Ubuntu20.0.4安装repo

国内三大免费源&#xff1a; 清华大学&#xff1a;清华大学开源软件镜像站 | Tsinghua Open Source Mirror中国科技大学&#xff1a;USTC Open Source Software Mirror阿里云&#xff1a;阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 repo只在清华源网站里搜到&#xff1a;…

【软件测试】:软件测试实战

1. ⾃动化实施步骤 1.1 编写web测试⽤例 1.2 ⾃动化测试脚本开发 common public class AutotestUtils {public static EdgeDriver driver;// 创建驱动对象public static EdgeDriver createDriver(){// 驱动对象已经创建好了 / 没有创建if( driver null){driver new EdgeDr…

unittest自动化测试实战

&#x1f345; 点击文末小卡片&#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 为什么要学习unittest 按照测试阶段来划分&#xff0c;可以将测试分为单元测试、集成测试、系统测试和验收测试。单元测试是指对软件中的最小可测试单元在与程…

leetcode3.无重复字符的最长字串

采用滑动窗口方法 class Solution { public:int lengthOfLongestSubstring(string s) {int ns.size();if(n0)return 0;int result0;unordered_set<char> set;set.insert(s[0]);for(int i0,j0;i<n;i){while(j1<n&&set.find(s[j1])set.end()){set.insert(s[…

3.25-2request库

request库 一、介绍request库 &#xff08;1&#xff09;requests是用python语言编写的简单易用的http库&#xff0c;用来做接口测试的库&#xff1b; &#xff08;2&#xff09;接口测试自动化库有哪些&#xff1f; requests、urllib 、urllib2、urllib3、 httplib 等&…

Docker-Volume数据卷详讲

Docker数据卷-Volume 一&#xff1a;Volume是什么&#xff0c;用来做什么的 当删除docker容器时&#xff0c;容器内部的文件就会跟随容器所销毁&#xff0c;在生产环境中我们需要将数据持久化保存&#xff0c;就催生了将容器内部的数据保存在宿主机的需求&#xff0c;volume …

蓝桥杯备考之 最长上升子序列问题(挖地雷)

这道题其实就是正常的最长上升子序列问题&#xff0c;但是我们还要把最优方案输出出来&#xff0c;我们可以用个pre数组来维护就行了&#xff0c;每当我们更新以i为结尾的最长子序列&#xff0c;如果i是接在1到i-1某个点后面的话就把前面的点存到pre里面 最后我们把pre倒着打印…