当前位置: 首页 > news >正文

【Linux】同步原理剖析及模拟BlockQueue生产消费模型

📢博客主页:https://blog.csdn.net/2301_779549673
📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨

在这里插入图片描述

在这里插入图片描述

文章目录

  • 📢前言
  • 🏳️‍🌈一、线程同步概念
  • 🏳️‍🌈二、为什么需要线程同步?
    • 2.1 防止数据竞争(Data Race)​
    • 2.2 保证操作的原子性
    • 2.​3 协调线程间的执行顺序
    • 2.​4 避免资源争用(如文件、网络连接)​
  • 🏳️‍🌈线程同步的常见手段
  • 🏳️‍🌈三、什么是生产消费者模型
    • 3.1 三种关系
    • 3.2 两个角色
    • 3.3 一个场景
  • 🏳️‍🌈四、以阻塞队列模拟多生产消费者模型
    • 4.1 成员名
    • 4.2 构造函数和析构函数
    • 4.3 模拟的生产者和消费者
    • 4.4 模拟生产、消费者过程
  • 🏳️‍🌈五、整体代码
    • 5.1 BlockQueue.hpp
    • 5.2 Main.cc
    • 5.3 Makefile
  • 👥总结


📢前言

紧接上一回的 从互斥原理到C++ RAII封装实践 笔者这回介绍一下线程中几乎与互斥一样重要的同步原理,

还有一点,笔者之后的封装都会使用之前博客中封装好的容器,需要的可以去仓库或者前面的博客中自取。

所需所用的都放在了这个仓库中
在这里插入图片描述


🏳️‍🌈一、线程同步概念

条件变量:当一个线程互斥地访问某个变量时,它可能发现在其它线程改变状态之前,它什么也做不了。例如一个线程访问队列时,发现队列为空,它只能等待,只到其它线程将一个节点添加到队列中。这种情况就需要用到条件变量。

线程同步 指在多线程编程中,通过特定机制协调多个线程的执行顺序,确保它们对共享资源​(如内存、文件、硬件等)的访问安全有序。核心目标是防止并发访问导致的数据混乱、逻辑错误或资源冲突

🏳️‍🌈二、为什么需要线程同步?

2.1 防止数据竞争(Data Race)​

​问题:多个线程同时读写共享数据时,执行顺序不确定,可能导致数据不一致。

int balance = 100;  // 共享变量// 线程A执行:存入200
balance += 200;  // 线程B执行:取出150
balance -= 150;
  • 未同步时:若线程A和B同时读取balance=100,最终结果可能是100+200-150=150(正确应为150)或100-150+200=150,但若操作交叉执行(如A读后B写),可能得到错误值(如-50)。

2.2 保证操作的原子性

​问题:单个操作(如i++)在底层可能对应多条机器指令,线程切换会导致操作未完成就被中断

; x86的i++实际步骤:
mov eax, [i]  ; 读取i到寄存器
inc eax       ; 寄存器加1
mov [i], eax  ; 写回内存
  • 若线程A执行到inc eax后被切换,线程B修改了i,线程A恢复后会将旧值写回,导致结果错误。

2.​3 协调线程间的执行顺序

​场景:某些任务需要线程按特定顺序执行。
​生产者-消费者模型:消费者线程需等待生产者生成数据后再读取。
​任务依赖:线程B必须在线程A完成初始化后才能执行。

2.​4 避免资源争用(如文件、网络连接)​

​问题:多个线程同时写入同一文件或占用同一网络端口,会导致数据错乱或程序崩溃。

🏳️‍🌈线程同步的常见手段

在这里插入图片描述
同步问题的严重后果
​数据不一致:程序输出错误,如银行账户余额异常。
程序崩溃:多线程同时释放内存导致双重释放(Double Free)。
死锁(Deadlock)​:线程互相等待对方释放锁,导致永久阻塞。

说白了,线程同步就是一种为了统一管理生产消费者模型的一种机制

🏳️‍🌈三、什么是生产消费者模型

在这里插入图片描述

3.1 三种关系

在这里插入图片描述

3.2 两个角色

生产者,模拟是同数据的那方
消费者,取走数据的那方

3.3 一个场景

所有生产消费所用的数据都是在中间的 “超市” 中进行
在这里插入图片描述

🏳️‍🌈四、以阻塞队列模拟多生产消费者模型

下图是以阻塞队列模拟多生产消费者模型的基本过程

也就是有两类线程(生产者和消费者),从同一个场景(blockqueue)中放入和拿出数据的过程
在这里插入图片描述

4.1 成员名

我们利用现有的库函数对环境进行一下封装,再利用一个队列模拟临界资源

    private:std::queue<T> _q;               // 保存数据的容器,临界资源int _cap;                       // bq最大容量pthread_mutex_t _mutex;         // 互斥pthread_cond_t _productor_cond; // 生产者条件变量pthread_cond_t _consumer_cond;  // 消费者条件变量int _cwait_num;                 // 当前等待的消费者数量int _pwait_num;                 // 当前等待的生产者数量};

4.2 构造函数和析构函数

		BlockQueue(int cap = gcap) : _cap(cap), _cwait_num(0), _pwait_num(0){pthread_mutex_init(&_mutex, nullptr);         // 创建互斥锁pthread_cond_init(&_productor_cond, nullptr); // 生产者条件变量pthread_cond_init(&_consumer_cond, nullptr);  // 消费者条件变量}~BlockQueue(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_productor_cond);pthread_cond_destroy(&_consumer_cond);}

4.3 模拟的生产者和消费者

void Equeue(const T &in) // 生产者{pthread_mutex_lock(&_mutex);// 你想放数据,就能放数据吗??生产数据是有条件的!// 结论1: 在临界区中等待是必然的(目前)while (IsFull()) // 5. 对条件进行判断,为了防止伪唤醒,我们通常使用while进行判断!{std::cout << "生产者进入等待..." << std::endl;// 2. 等是,释放_mutex_pwait_num++;pthread_cond_wait(&_productor_cond, &_mutex); // wait的时候,必定是持有锁的!!是有问题的!_pwait_num--;// 3. 返回,线程被唤醒&&重新申请并持有锁(它会在临界区内醒来!)std::cout << "生产者被唤醒..." << std::endl;}// 4. if(IsFull())不满足 || 线程被唤醒_q.push(in); // 生产// 肯定有数据!if(_cwait_num){std::cout << "叫醒消费者" << std::endl;pthread_cond_signal(&_consumer_cond);}pthread_mutex_unlock(&_mutex);}void Pop(T *out) // 消费者{pthread_mutex_lock(&_mutex);while(IsEmpty()){std::cout << "消费者进入等待..." << std::endl;_cwait_num++;pthread_cond_wait(&_consumer_cond, &_mutex); // 伪唤醒_cwait_num--;std::cout << "消费者被唤醒..." << std::endl;}// 4. if(IsEmpty())不满足 || 线程被唤醒*out = _q.front();_q.pop();// 肯定有空间if(_pwait_num){std::cout << "叫醒生产者" << std::endl;pthread_cond_signal(&_productor_cond);}pthread_mutex_unlock(&_mutex);}

4.4 模拟生产、消费者过程

我们假设生产速度小于消费速度,相当于我们没生产一个对象后需要花费一定的时间,但是消费者一直就绪,就要等生产者生产出来

void *Consumer(void *args)
{BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(args);while(true){int data;// 1. 从bq拿到数据bq->Pop(&data);// 2.做处理printf("Consumer, 消费了一个数据: %d\n", data);}
}void *Productor(void *args)
{BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(args);int data = 10;while (true){sleep(2);// 1. 从外部获取数据// data = 10; // 有数据???// 2. 生产到bq中bq->Equeue(data);printf("producter 生产了一个数据: %d\n", data);data++;}
}

🏳️‍🌈五、整体代码

5.1 BlockQueue.hpp

#pragma once#include <iostream>
#include <queue>
#include <pthread.h>namespace BlockQueueModule
{static const int gcap = 10;template <typename T>class BlockQueue{private:bool IsFull() { return _q.size() == _cap; }bool IsEmpty() { return _q.empty(); }public:BlockQueue(int cap = gcap) : _cap(cap), _cwait_num(0), _pwait_num(0){pthread_mutex_init(&_mutex, nullptr);         // 创建互斥锁pthread_cond_init(&_productor_cond, nullptr); // 生产者条件变量pthread_cond_init(&_consumer_cond, nullptr);  // 消费者条件变量}void Equeue(const T &in) // 生产者{pthread_mutex_lock(&_mutex);// 你想放数据,就能放数据吗??生产数据是有条件的!// 结论1: 在临界区中等待是必然的(目前)while (IsFull()) // 5. 对条件进行判断,为了防止伪唤醒,我们通常使用while进行判断!{std::cout << "生产者进入等待..." << std::endl;// 2. 等是,释放_mutex_pwait_num++;pthread_cond_wait(&_productor_cond, &_mutex); // wait的时候,必定是持有锁的!!是有问题的!_pwait_num--;// 3. 返回,线程被唤醒&&重新申请并持有锁(它会在临界区内醒来!)std::cout << "生产者被唤醒..." << std::endl;}// 4. if(IsFull())不满足 || 线程被唤醒_q.push(in); // 生产// 肯定有数据!if(_cwait_num){std::cout << "叫醒消费者" << std::endl;pthread_cond_signal(&_consumer_cond);}pthread_mutex_unlock(&_mutex);}void Pop(T *out) // 消费者{pthread_mutex_lock(&_mutex);while(IsEmpty()){std::cout << "消费者进入等待..." << std::endl;_cwait_num++;pthread_cond_wait(&_consumer_cond, &_mutex); // 伪唤醒_cwait_num--;std::cout << "消费者被唤醒..." << std::endl;}// 4. if(IsEmpty())不满足 || 线程被唤醒*out = _q.front();_q.pop();// 肯定有空间if(_pwait_num){std::cout << "叫醒生产者" << std::endl;pthread_cond_signal(&_productor_cond);}pthread_mutex_unlock(&_mutex);}~BlockQueue(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_productor_cond);pthread_cond_destroy(&_consumer_cond);}private:std::queue<T> _q;               // 保存数据的容器,临界资源int _cap;                       // bq最大容量pthread_mutex_t _mutex;         // 互斥pthread_cond_t _productor_cond; // 生产者条件变量pthread_cond_t _consumer_cond;  // 消费者条件变量int _cwait_num;                 // 当前等待的消费者数量int _pwait_num;                 // 当前等待的生产者数量};
}

5.2 Main.cc

#include "BlockQueue.hpp"
#include <pthread.h>
#include <unistd.h>using namespace BlockQueueModule;void *Consumer(void *args)
{BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(args);while(true){int data;// 1. 从bq拿到数据bq->Pop(&data);// 2.做处理printf("Consumer, 消费了一个数据: %d\n", data);}
}void *Productor(void *args)
{BlockQueue<int> *bq = static_cast<BlockQueue<int> *>(args);int data = 10;while (true){sleep(2);// 1. 从外部获取数据// data = 10; // 有数据???// 2. 生产到bq中bq->Equeue(data);printf("producter 生产了一个数据: %d\n", data);data++;}
}int main()
{// 交易场所,不仅仅可以用来进行传递数据// 传递任务!!!v1: 对象 v2BlockQueue<int> *bq = new BlockQueue<int>(5); // 共享资源 -> 临界资源// 单生产,单消费pthread_t c1, p1, c2, p2, p3;pthread_create(&c1, nullptr, Consumer, bq);pthread_create(&c2, nullptr, Consumer, bq);pthread_create(&p1, nullptr, Productor, bq);pthread_create(&p2, nullptr, Productor, bq);pthread_create(&p3, nullptr, Productor, bq);pthread_join(c1, nullptr);pthread_join(c2, nullptr);pthread_join(p1, nullptr);pthread_join(p2, nullptr);pthread_join(p3, nullptr);delete bq;return 0;
}

5.3 Makefile

bin=bq
cc=g++
src=$(wildcard *.cc)
obj=$(src:.cc=.o)$(bin):$(obj)$(cc) -o $@ $^ -lpthread
%.o:%.cc$(cc) -c $< -std=c++17.PHONY:clean
clean:rm -f $(bin) $(obj).PHONY:test
test:echo $(src)echo $(obj)

👥总结

本篇博文对 同步原理剖析及模拟多消费者模型 做了一个较为详细的介绍,不知道对你有没有帮助呢

觉得博主写得还不错的三连支持下吧!会继续努力的~

请添加图片描述

相关文章:

【Linux】同步原理剖析及模拟BlockQueue生产消费模型

&#x1f4e2;博客主页&#xff1a;https://blog.csdn.net/2301_779549673 &#x1f4e2;博客仓库&#xff1a;https://gitee.com/JohnKingW/linux_test/tree/master/lesson &#x1f4e2;欢迎点赞 &#x1f44d; 收藏 ⭐留言 &#x1f4dd; 如有错误敬请指正&#xff01; &…...

【AVRCP】GOEP互操作性深度解析:蓝牙封面艺术传输的技术实现与演进

目录 一、技术基础&#xff1a;协议架构与核心概念 1.1 GOEP协议体系解析 1.2 IrOBEX协议关键技术 1.3 版本强制性要求 1.4 关键特性对比&#xff08;GOEP v2.0 vs v1.1&#xff09; 1.5 关键技术实现细节 1.6 GOEP v2.0互操作性要求 1.7 IrOBEX v1.5互操作性要求 二、…...

三分钟读懂微服务

一、什么是微服务 微服务&#xff0c;简单来说&#xff0c;就是把一个庞大复杂的软件系统&#xff0c;拆分成一个个小型的、独立的服务模块。打个比方&#xff0c;一个大型商场就如同传统的单体架构软件系统&#xff0c;里面所有的店铺、设施都紧密关联在一起。而微服务架构下…...

《Oracle DBA入门实战:十大高频问题详解与避坑指南》

Oracle DBA 入门作业十问十答 本文为 Oracle DBA 入门作业整理&#xff0c;涵盖工具使用、配置管理及权限控制等核心知识点&#xff0c;适合新手快速上手。 如有疑问或补充&#xff0c;欢迎评论区交流&#xff01; 1. DBA 常用工具有哪些&#xff1f; Oracle Universal Instal…...

深入剖析 Android Compose 框架的自动动画:AnimatedVisibility 与 AnimatedContent(二十四)

深入剖析 Android Compose 框架的自动动画&#xff1a;AnimatedVisibility 与 AnimatedContent 引言 在 Android 应用开发中&#xff0c;动画是提升用户体验的重要手段。它能够让界面元素的显示与隐藏、状态的切换变得更加自然和流畅&#xff0c;避免生硬的变化给用户带来不佳…...

【线程安全问题的原因和方法】【java形式】【图片详解】

在本章节中采用实例图片的方式&#xff0c;以一个学习者的姿态进行描述问题解决问题&#xff0c;更加清晰明了&#xff0c;以及过程中会发问的问题都会一一进行呈现 目录 线程安全演示线程不安全情况图片解释&#xff1a; 将上述代码进行修改【从并行转化成穿行的方式】不会出…...

Cocos Creator Shader入门实战(六):使用setProperty动态设置材质属性,以及材质常用接口

引擎&#xff1a;3.8.5 您好&#xff0c;我是鹤九日&#xff01; 回顾 上篇文章&#xff0c;我们主要讲解了关于材质的使用&#xff0c;主要有这么几点&#xff1a; 一、没有Effect资源&#xff0c;材质无从说起。 二、材质的构建&#xff0c;支持编译器和代码的动态构建 三…...

编程题记录3

九宫幻方 题目链接&#xff1a;https://www.lanqiao.cn/problems/100/learning/?page1&first_category_id1&second_category_id3&tags%E7%9C%81%E8%B5%9B&tag_relationintersection 先旋转、镜像得到所有的情况&#xff0c;可以发现情况是可以暴力得出的。…...

Geotools自动识别SLD并生成图例图片实战-以Polygon数据为例

目录 前言 一、Geotools与SLD制图基础 1、SLD是什么 2、SLD有什么用 二、SLD文件的解析与读取 1、SLD结构介绍 2、SLD实例展示 3、SLD读取方法 三、图例生成与展示 1、图例生成流程 2、图例生成实战 3、图例生成展示 四、结论 前言 在地理信息系统&#xff08;GIS&…...

windows docker如何修改 默认的Container memory usage

参考:https://forums.docker.com/t/docker-on-windows-11-with-wsl2-does-not-use-the-memory-i-set-in-wslconfig/144404/3 参考:https://learn.microsoft.com/en-us/windows/wsl/wsl-config...

LabVIEW液压传动系统教学仿真平台

本文介绍了一种基于LabVIEW的液压传动系统教学仿真平台&#xff0c;该平台采用“老师讲解、线上仿真、线下操作”的复合实验模式&#xff0c;旨在提高实验教学的效率与安全性。通过实例验证&#xff0c;展示了该平台在教学和实际操作中的应用效果&#xff0c;同时也为液压传动系…...

Java实习生面试题(2025.3.23 be)

一、v-if与v-show的区别 v-show 和 v-if 都是 Vue 中的条件渲染指令&#xff0c;它们的主要区别在于渲染策略&#xff1a;v-if 会根据条件决定是否编译元素&#xff0c;而 v-show 则始终编译元素&#xff0c;只是通过改变 CSS 的 display 属性来控制显示与隐藏。 二、mybatis-…...

OpenCV第2课 OpenCV的组成结构与图片/视频的加载及展示

1.OpenCV 的组成结构 2.OpenCV 的具体模块 3. 图像的读取 4. 视频的读取 1.OpenCV 的组成结构 OpenCV 是由很多模块组成的,这些模块可以分成很多层: 最底层是基于硬件加速层(HAL)的各种硬件优化。再上一层是opencv_contrib 模块所包含的OpenCV 由其他开发人员所贡献的代…...

Blender导出fbx到Unity找不到贴图的问题

fbx导入Unity材质能不能找到贴图是一件玄学的事情。常见的情况是有些材质能找到&#xff0c;有些找不到&#xff1a; 可能有用的方法 解决方法1&#xff1a;把贴图文件复制过去&#xff0c;模型reimport&#xff1b; 解决方法2&#xff1a;导出时路径模式选复制&#xff0c;内…...

kafka的文章

1.面试的问题 要点 至多一次、恰好一次数据一致性超时重试、幂等消息顺序消息挤压延时消息 1.1 kafaka 生产消息的过程。 在消息发送的过程中&#xff0c;涉及到了两个线程&#xff0c;一个是main 线程&#xff0c;一个是sender 线程。在main 线程中创建了一个双端队列 Reco…...

Go常见问题与回答(下)

文章目录 1、通过指针变量 p 访问其成员变量 name&#xff0c;有哪几种方式&#xff1f;2、代码&#xff0c;说出结果3、扩容提&#xff0c;代码&#xff0c;说出结果4、指出下面这段代码的错误之处5、是否通过编译6、关于字符串连接&#xff0c;下面语法正确的是7、关于iota&a…...

vue3中如何缓存路由组件

在 Vue3 中缓存路由组件&#xff0c;主要借助<keep-alive>组件来实现&#xff0c;具体方法如下&#xff1a; 1. 全局缓存路由组件 在 App.vue 等根组件中&#xff0c;直接将<router-view>包裹在<keep-alive>标签内&#xff0c;这样所有的路由组件都会被缓存…...

云服务器怎么防御ddos攻击呢?

防御DDoS攻击是保障云服务器稳定运行的关键措施&#xff0c;以下是综合多种防护策略的详细方案&#xff1a; 1. 启用云服务商提供的DDoS防护服务 高防IP/流量清洗&#xff1a; 将业务流量接入云服务商的高防IP&#xff0c;由专业清洗中心过滤恶意流量&#xff0c;仅放行正常请求…...

Log4j2 的核心实现和源码分析

Log4j2 的核心实现和源码分析 1. 核心组件 1.1 Logger 功能:负责记录日志信息。实现:org.apache.logging.log4j.Logger 接口,org.apache.logging.log4j.core.Logger 类。1.2 Appender 功能:负责将日志信息输出到不同的目的地,如文件、控制台等。实现:org.apache.loggin…...

【深度学习】【目标检测】【OnnxRuntime】【C++】YOLOV3模型部署

【深度学习】【目标检测】【OnnxRuntime】【C】YOLOV3模型部署 提示:博主取舍了很多大佬的博文并亲测有效,分享笔记邀大家共同学习讨论 文章目录 【深度学习】【目标检测】【OnnxRuntime】【C】YOLOV3模型部署前言Windows平台搭建依赖环境模型转换--pytorch转onnxONNXRuntime推…...

四种跨模态行人重识别可视化方法

1.Gradcam 2.检索可视化 3.tsne图 4.距离分布 需要的私聊&#xff0c;代码需要付费...

8个DeepSeek文章润色指令

今天道叔给各位文字工作者安利DeepSeek的8个神仙级润色指令(附真实案例拆解)&#xff0c;建议搭配冰美式食用更佳↓↓↓ 一、【学术黑话翻译器】 适用场景&#xff1a;给投资人看的BP/行业白皮书/专家访谈实录 指令公式&#xff1a;"将以下内容转化为通俗易懂的行业洞察…...

解决PowerShell下Git中文乱码问题

解决PowerShell下Git中文乱码问题 在使用Git进行版本控制时&#xff0c;许多开发者可能会遇到中文乱码的问题&#xff0c;尤其是在Windows环境下使用PowerShell时。这不仅影响代码的阅读和提交&#xff0c;还可能导致一些不可预见的错误。本文将详细探讨如何在PowerShell下解决…...

oracle数据库(数据库启动关闭/sqlplus登录及基本操作/设置字符集/distinct去重)

目录 1. Oracle数据库启动 2. Oracle数据库关闭 3. sqlplus登录Oracle数据库 3.1 使用sqlplus登录Oracle数据库 3.2 使用sqlplus登录Oracle数据库 3.3 远程登录 3.4 解锁用户 3.5 修改用户密码 3.6 查看当前语言环境 4. sqlplus基本操作 4.1 显示当前用户 4.2 查看当前用户…...

mapreduce时,客户端做哪些事

在MapReduce过程中&#xff0c;客户端&#xff08;Client&#xff09;是用户提交作业的入口&#xff0c;负责作业的初始化、配置、资源提交和作业监控。以下是客户端在整个流程中的具体职责和操作步骤&#xff1a; 1. 作业配置与参数解析 设置作业属性&#xff1a; 定义MapRed…...

DeepBI:重构流量逻辑,助力亚马逊广告实现高效流量增长

在日益激烈的跨境电商竞争环境中&#xff0c;广告投放早已从“粗放撒网”走向“精细化运营”。尤其是在亚马逊这样一个成熟且竞争白热化的平台&#xff0c;如何在广告预算有限的前提下实现高效曝光、精准触达、稳定转化&#xff0c;成为众多卖家和运营团队面临的核心挑战。 De…...

Linux内核的页面错误:原因与解决方案

当程序访问虚拟内存中的一个页面时&#xff0c;如果该页面当前不在物理内存中&#xff0c;就会触发一个称为"page fault"&#xff08;页异常&#xff09;的异常。操作系统需要处理这个异常&#xff0c;并将所需页面从磁盘加载到内存中。实现虚存管理的一个关键是page…...

LORA 中的 梯度外积是什么意思; 方差和协方差的实际含义:衡量变量的离散程度和变量间的线性相关性

LORA 中的 梯度外积是什么意思 目录 LORA 中的 梯度外积是什么意思**一、梯度外积的定义****二、示例说明****步骤1:计算单样本梯度****步骤2:计算梯度外积****三、梯度外积的作用****四、总结**方差和协方差的实际含义:衡量变量的离散程度和变量间的线性相关性**一、方差(…...

XSS复现漏洞简单前八关靶场

靶场不需要安装任意环境 链接如下&#xff1a;XSS Game - Learning XSS Made Simple! | Created by PwnFunction 目录 XSS Game 第一关&#xff1a;Ma Spaghet! 第二关&#xff1a;Jefff 第三关&#xff1a;Ugandan Knuckles 第四关&#xff1a;Ricardo Milos 第五关&am…...

3.24-3 接口测试断言

一.postman 断言 1.断言再test中 #状态码是否等于200 tests["Status code is 200"] responseCode.code 200; #断言响应时间小于200ms tests["Response time is less than 200ms"] responseTime < 200; #断言响应体包含内容 tests["Body…...

《鸿蒙携手AI:解锁智慧出行底层逻辑》

在科技飞速发展的当下&#xff0c;智慧出行成为人们对未来交通的美好期许&#xff0c;而鸿蒙系统与人工智能的深度融合&#xff0c;正为这一愿景的实现提供强大助力。从技术原理角度深入剖析&#xff0c;鸿蒙系统究竟如何支撑人工智能在智慧出行场景中的应用呢&#xff1f;这背…...

【AVRCP】探寻AVRCP控制互操作性:连接、命令与设备交互

目录 一、AVCTP连接管理 1.1 AVCTP连接建立 1.2 AVCTP连接释放 二、AV/C命令的操作流程 2.1 AV/C命令交换流程 2.2 AV/C命令类型 三、AVRCP特定命令 四、AVRCP浏览命令 五、OBEX连接管理 5.1 OBEX连接建立 5.2 OBEX连接释放 六、总结 七、参考资料 AVRCP对于实现设…...

Mybatis-Plus知识点详解

Mybatis-plus(简称MP),基于Mybatis的增强工具,保留了Mybatis的所有功能,同时增加了通用的CRUD,条件构造器,分页插件等等实用工具 特性 即拿即用:通过通用Mapper和Service,无需编写XML既可以完成单表CURE操作 Lambda支持:使用Lambda表达式构建查询条件,避免硬编码字段名,提升代…...

紧凑交叉引用表

嗯&#xff0c;用户问的是“compact xref table”&#xff0c;也就是紧凑型交叉引用表。我之前在回答中提到过交叉引用流&#xff08;XRef Stream&#xff09;&#xff0c;但可能需要更详细地解释两者的区别和联系。根据搜索结果中的网页1&#xff0c;传统的Xref表以文本形式存…...

CMake 详解:跨平台构建系统的入门与进阶

目录 一、相关知识点 1. 什么是cmake&#xff0c;为什么使用&#xff1f; 2. 构建过程 二、CMake使用流程 1. 创建 CMakeLists.txt 文件 2. 配置构建目录 3. 运行cmake 4. 运行make编译 一、相关知识点 1. 什么是cmake&#xff0c;为什么使用&#xff1f; CMake 是一个开…...

【架构设计】学习路径

掌握前置知识后&#xff0c;学习架构设计需要从理论认知到实践落地逐步推进。以下是系统化的学习路径&#xff0c;结合具体案例与实操建议&#xff0c;帮助你快速进阶&#xff1a; 一、构建架构思维基础 1. 理解架构设计的核心目标 关键问题驱动设计&#xff1a; 每个架构决策…...

14、Python 枚举与类型注解进阶

Python 枚举与类型注解进阶 文章概述 本文深入探讨Python中枚举&#xff08;Enum&#xff09;与类型注解的高级应用场景。通过剖析Enum类的核心特性、dataclass装饰器的工程实践、静态类型检查工具mypy的集成使用&#xff0c;结合状态机等实际案例&#xff0c;系统性地提升代…...

C语言 【实现电脑关机小游戏】非常好玩

引言 在时间限制内做出正确的回答&#xff0c;时间一到&#xff0c;电脑自动关机&#xff0c;听起来是不是很有意思&#xff0c;下面来看看怎么实现吧。 注意&#xff1a;该游戏只在windows系统下可以玩&#xff0c; 一、游戏原理&#xff1a; 在Windows系统下&#xff0c;通…...

【蓝桥杯速成】| 11.回溯 之 子集问题

题目一&#xff1a;子集 问题描述 78. 子集 - 力扣&#xff08;LeetCode&#xff09; 给你一个整数数组 nums &#xff0c;数组中的元素 互不相同 。返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。 示例…...

统计矩的高阶推广:经验还是理论推导?

矩的发展既是经验总结的结果&#xff0c;也是数学理论推导的产物。研究者们在分析数据、描述物理现象的过程中&#xff0c;发现了低阶矩与日常物理概念&#xff08;如质心、惯性&#xff09;之间的紧密联系&#xff0c;而高阶矩的应用往往出现在更复杂的数学体系中&#xff0c;…...

SpringBoot2集成Elasticsearch8(使用spring-boot-starter-data-elasticsearch)

写在前面 使用spring-boot-starter-data-elasticsearch集成Elasticsearch8&#xff1f; What? 官方写的不支持啊&#xff1f;让我们来看下官方给出的版本建议。 官方地址&#xff1a; https://docs.spring.io/spring-data/elasticsearch/reference/elasticsearch/versions.…...

Postgresql源码(142)子查询提升pull_up_sublinks

1 案例 drop table t_fun01; create table t_fun01 (image_id numeric primary key, content_id varchar(50), file_code varchar(20)); create index idx3 on t_fun01(content_id); create index idx4 on t_fun01(file_code); insert into t_fun01 select t.i, t.i%10, t.i%1…...

sonar代码检测研究及平台搭建

为了实现提交代码自动检测代码缺陷&#xff0c;本文介绍了一种将jenkins与gitlab集成的自动检测机制&#xff0c;如需应用于生产级开发流程&#xff0c;可在此基础上进行功能丰富和扩展,本文仅进行了原理性搭建。 一、基础环境准备 与sonar配合使用的jenkins和gitlab基础软件…...

清华大学:DeepSeek从入门到精通系列教程1-9讲(持续更新中)|大礼包免费下载

导 读INTRODUCTION 今天分享由清华大学新闻与传播学院、人工智能学院双聘教授沈阳老师团队倾力打造的《DeepSeek从入门到精通系列教程1-9讲&#xff08;持续更新中&#xff09;》&#xff0c;包含&#xff1a;《DeepSeek&#xff1a;从入门到精通》《DeepSeek如何赋能职场应用》…...

使用Python可视化图结构:从GraphML文件生成节点关系图(lightrag 生成)

引言 在数据可视化领域&#xff0c;图结构&#xff08;Graph&#xff09;常用于展示实体间的复杂关系。例如&#xff0c;文学分析中的角色关系、社交网络中的用户互动等。本文将通过一个实际案例&#xff0c;演示如何使用 NetworkX 和 Matplotlib 从 GraphML 文件生成节点关系…...

排序复习_代码纯享

头文件 #pragma once #include<iostream> #include<vector> #include<utility> using std::vector; using std::cout; using std::cin; using std::endl; using std::swap;//插入排序 //1、直接插入排序&#xff08;稳定&#xff09; void InsertSort(vecto…...

Docker Hub Mirror 终极解决方案——0成本,超高速!

CNB Docker Mirror (cdm) CNB Docker Mirror 是一个基于 CNB 的 Docker 镜像加速工具&#xff0c;提供本地镜像加速功能。 功能特性 镜像加速&#xff1a;在本地启动连接到 CNB 环境的 Docker 镜像加速服务&#xff0c;然后通过配置 Docker 客户端实现镜像加速下载自动重连&…...

2000-2019年各省地方财政车船税数据

2000-2019年各省地方财政车船税数据 1、时间&#xff1a;2000-2019年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;行政区划代码、地区、年份、地方财政车船税 4、范围&#xff1a;31省 5、指标说明&#xff1a;车船税作为地方财政的重要组成部分&#x…...

c#处理算数溢出的情况

在C#中&#xff0c;算术运算的溢出处理可以通过 checked 和 unchecked 关键字控制&#xff0c;默认行为是 静默截断&#xff08;unchecked模式&#xff09;&#xff0c;但可以通过配置或代码块显式调整。以下是详细说明&#xff1a; 1. 默认行为&#xff08;unchecked模式&…...

Java「Deque」 方法详解:从入门到实战

Java Deque 各种方法解析&#xff1a;从入门到实战 在 Java 编程中&#xff0c;Deque&#xff08;双端队列&#xff09;是一个功能强大的数据结构&#xff0c;允许开发者从队列的两端高效地添加、删除和检查元素。作为 java.util 包中的一部分&#xff0c;Deque 接口继承自 Qu…...