【Linux】条件变量封装类及环形队列的实现
📢博客主页:https://blog.csdn.net/2301_779549673
📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨
文章目录
- 📢前言
- 🏳️🌈一、条件变量 Cond
- 1.1 条件变量的本质
- 1.2 核心作用
- 🏳️🌈二、条件变量封装类
- 2.1 类定义
- 2.2 构造函数
- 2.3 Wait 方法
- 2.4 Notify 和 NotifyAll
- 2.5 析构函数
- 2.6 整体代码
- 2.7 示例用法
- 🏳️🌈三、POSIX 信号量
- 3.1 Sem类核心功能
- 3.2 设计意义
- 3.3 Sem类封装
- 🏳️🌈四、环形队列的逻辑及实现
- 4.1 核心设计
- 4.2 成员变量
- 4.3 核心接口
- 4.3.1 构造函数
- 4.3.2Equeue(生产者接口)
- 4.3.3 Pop(消费者接口)
- 4.4 同步机制
- 4.4.1 信号量控制
- 4.4.2 互斥锁保护
- 4.5 整体代码
- 4.6 测试代码
- 👥总结
📢前言
紧接上回 BlockQueue生产消费模型 的实现,这篇文章,笔者来介绍一下 条件变量 的意义和作用,然后进行 封装,并实现 BlockQueue 的加强版 环形阻塞队列 RingBuffer
🏳️🌈一、条件变量 Cond
1.1 条件变量的本质
条件变量 是 线程间的通信机制,用于在 特定条件不满足时挂起线程,并在条件满足时 唤醒线程继续执行。它必须与 **互斥锁(Mutex)** 配合使用,确保操作的原子性。
1.2 核心作用
-
避免忙等待(Busy Waiting)
问题:没有条件变量时,线程需反复检查条件是否满足(while(条件不满足)),浪费CPU资源。
解决:条件变量让线程在条件不满足时主动休眠,直到被其他线程唤醒。 -
实现线程间协作
生产者-消费者模型:生产者通知消费者“数据已准备好”,消费者通知生产者“缓冲区有空位”。
任务队列:工作线程在队列为空时休眠,主线程添加任务后唤醒工作线程。 -
保证操作的原子性
通过 互斥锁 + 条件变量
的组合,确保线程在检查条件和进入等待状态的整个过程是原子的,避免竞态条件。
🏳️🌈二、条件变量封装类
头文件和命名空间:
- 包含 和 <pthread.h>,后者提供 POSIX 线程操作。
- 使用
LockModule
命名空间中的Mutex
类,表示互斥锁。
2.1 类定义
class Cond {
public:Cond();void Wait(Mutex &mutex);void Notify();void NotifyAll();~Cond();
private:pthread_cond_t _cond;
};
封装了 pthread_cond_t
,提供初始化、等待、通知和销毁功能
2.2 构造函数
Cond() {int n = ::pthread_cond_init(&_cond, nullptr);(void)n; // 忽略返回值
}
- 调用
pthread_cond_init
初始化条件变量。 - 返回值
n
被忽略,实际应用中应检查错误(如返回非零表示失败)。
2.3 Wait 方法
void Wait(Mutex &mutex) {int n = ::pthread_cond_wait(&_cond, mutex.LockPtr());
}
作用:使当前线程等待条件变量,并释放关联的互斥锁。
参数:Mutex
对象的引用,调用其 LockPtr()
获取底层 pthread_mutex_t*
。
流程:
- 调用线程必须已锁定
mutex
。 pthread_cond_wait
自动释放mutex
并阻塞,直到被唤醒。- 被唤醒后重新获取
mutex
,继续执行。
2.4 Notify 和 NotifyAll
void Notify() {::pthread_cond_signal(&_cond); // 唤醒一个等待线程
}
void NotifyAll() {::pthread_cond_broadcast(&_cond); // 唤醒所有等待线程
}
区别:
Notify()
唤醒至少一个等待线程。NotifyAll()
唤醒所有等待线程。- 应在持有相同互斥锁时调用,以避免竞态条件
2.5 析构函数
~Cond() {::pthread_cond_destroy(&_cond); // 销毁条件变量
}
确保没有线程等待时销毁,否则行为未定义
2.6 整体代码
Mutex.hpp
#pragma once
#include <iostream>
#include <pthread.h> // POSIX线程库头文件namespace LockModule
{// 互斥锁封装类(不可拷贝构造/赋值)class Mutex{public:// 禁止拷贝(保护系统锁资源)Mutex(const Mutex&) = delete;const Mutex& operator = (const Mutex&) = delete;// 构造函数:初始化POSIX互斥锁Mutex(){// 初始化互斥锁属性为默认值int n = ::pthread_mutex_init(&_lock, nullptr);(void)n; // 实际开发建议处理错误码}// 析构函数:销毁锁资源~Mutex(){// 确保锁已处于未锁定状态int n = ::pthread_mutex_destroy(&_lock);(void)n; // 生产环境应检查返回值}// 加锁操作(阻塞直至获取锁)void Lock(){// 可能返回EDEADLK(死锁检测)等错误码int n = ::pthread_mutex_lock(&_lock);(void)n; // 简化处理,实际建议抛异常或记录日志}// 解锁操作(必须由锁持有者调用)void Unlock(){// 未持有锁时解锁将返回EPERMint n = ::pthread_mutex_unlock(&_lock);(void)n; }// 获取底层锁指针(可用于自定义条件变量)pthread_mutex_t *LockPtr(){return &_lock;}private:pthread_mutex_t _lock; // 底层锁对象};// RAII锁守卫(自动管理锁生命周期)class LockGuard{public:// 构造时加锁(必须传入已初始化的Mutex引用)LockGuard(Mutex &mtx):_mtx(mtx){_mtx.Lock(); // 进入临界区}// 析构时自动解锁(异常安全保证)~LockGuard(){_mtx.Unlock(); // 离开作用域自动释放}private:Mutex &_mtx; // 引用方式持有,避免拷贝导致未定义行为};
}
Cond.hpp
#pragma once#include <iostream>
#include <pthread.h>#include "Mutex.hpp"namespace CondModule{using namespace LockModule;class Cond{public:Cond(){int n = ::pthread_cond_init(&_cond, nullptr);(void)n;}void Wait(Mutex& mutex){// pthread_mutex_lock() 的作用是 锁定互斥锁,直到成功为止。// 第一个参数 cond 是一个条件变量的标识符,第二个参数 mutex 是一个互斥锁的标识符。// pthread_cond_wait() 用来等待条件变量 cond 被 pthread_cond_signal() 或 pthread_cond_broadcast() 唤醒。// 它将阻塞调用线程,直到被唤醒或被中断。// 返回值是 0 表示成功,其他值表示出错。// 出错时,errno 被设置。// 成功时,调用线程获得互斥锁 mutex,直到被 pthread_cond_signal() 或 pthread_cond_broadcast() 唤醒。int n = ::pthread_cond_wait(&_cond, mutex.LockPtr());(void)n;}void Notify(){// pthread_cond_signal() 用来唤醒一个正在等待条件变量的线程。// 第一个参数 cond 是一个条件变量的标识符。// 返回值是 0 表示成功,其他值表示出错。// 出错时,errno 被设置。// 成功时,一个正在等待条件变量的线程被唤醒。int n = ::pthread_cond_signal(&_cond);(void)n;}void NotifyAll(){// pthread_cond_broadcast() 用来唤醒所有正在等待条件变量的线程。// 第一个参数 cond 是一个条件变量的标识符。// 返回值是 0 表示成功,其他值表示出错。// 出错时,errno 被设置。// 成功时,所有正在等待条件变量的线程被唤醒。int n = ::pthread_cond_broadcast(&_cond);(void)n;}~Cond(){int n = ::pthread_cond_destroy(&_cond);(void)n;}private:pthread_cond_t _cond;};
}
2.7 示例用法
Mutex mutex;
Cond cond;
std::queue<int> buffer;// 生产者线程
void producer() {mutex.Lock();while (buffer.full()) {cond.Wait(mutex); // 等待缓冲区非满}buffer.push(1);cond.Notify(); // 通知消费者mutex.Unlock();
}// 消费者线程
void consumer() {mutex.Lock();while (buffer.empty()) {cond.Wait(mutex); // 等待缓冲区非空}buffer.pop();cond.Notify(); // 通知生产者mutex.Unlock();
}
🏳️🌈三、POSIX 信号量
POSIX信号量 和 SystemV信号量 作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。但POSIX可以用于线程间同步。
因此我们可以封装一个 Sem类 来统筹管理 POSIX信号量
扮演 线程同步协调者 的角色,通过 信号量机制 精准控制生产与消费的节奏,确保缓冲区的线程安全与高效运作。其设计不仅简化了复杂的同步逻辑,还通过 封装 和 *RAII机制 *提升了代码的可靠性和可维护性,是多线程编程中资源同步的典范实现。
3.1 Sem类核心功能
用于简化 POSIX 信号量的使用。其主要功能如下:
- 初始化:创建并初始化信号量。
- P 操作(P()):申请资源(信号量减 1),若资源不足则阻塞。
- V 操作(V()):释放资源(信号量加 1),唤醒等待线程。
- 销毁:清理信号量资源。
3.2 设计意义
- 简化信号量操作
- 封装底层 API:将
sem_init
、sem_wait
、sem_post
、sem_destroy
封装为类方法,隐藏实现细节。 - 统一接口:通过
P()
和V()
提供直观的语义(“申请”和“释放”)。
- 提高代码可维护性
RAII 机制:构造函数初始化资源,析构函数自动释放,避免资源泄漏。
{Sem sem(5); // 信号量初始化sem.P(); // 使用信号量
} // 作用域结束自动调用 ~Sem()
- 支持多种同步场景
通过调整初始值value
,可适配不同场景:
- 互斥锁(Mutex):value = 1(二元信号量)。
- 资源池:value = N(表示最多允许 N 个线程同时访问资源)。
- 生产者-消费者模型:通过两个信号量分别控制缓冲区空间和数据数量。
3.3 Sem类封装
#pragma once
#include <semaphore.h>namespace SemModule{int defaultsemval = 1;class Sem{public:Sem(int value = defaultsemval) : _init_value(value){sem_init(&sem, 0, value);}void P(){::sem_wait(&sem);}void V(){::sem_post(&sem);}~Sem(){::sem_destroy(&sem);}private:sem_t sem;int _init_value;};
}
🏳️🌈四、环形队列的逻辑及实现
4.1 核心设计
这是一个基于 信号量(Semaphore)
和 互斥锁(Mutex)
的线程安全环形队列(Ring Buffer
),用于实现 生产者-消费者模型。通过以下机制确保线程安全:
信号量控制:空间信号量(_spacesem
)控制可用空间,数据信号量(_datasem
)控制可消费数据。
互斥锁保护:生产者和消费者各自拥有独立的锁(_p_lock
和 _c_lock
),支持多生产者和多消费者并发操作。
4.2 成员变量
4.3 核心接口
4.3.1 构造函数
RingBuffer(int cap): _ring(cap), // 初始化缓冲区容量_cap(cap), // 记录总容量_p_step(0), // 生产者起始位置_c_step(0), // 消费者起始位置_datasem(0), // 初始无可消费数据_spacesem(cap) {} // 初始空间=总容量
作用:初始化缓冲区及相关同步机制
4.3.2Equeue(生产者接口)
void Equeue(const T &in) {_spacesem.P(); // 等待可用空间(信号量-1){LockGuard lockguard(_p_lock); // 加生产者锁_ring[_p_step] = in; // 写入数据_p_step = (_p_step + 1) % _cap; // 环形移动}_datasem.V(); // 增加可消费数据(信号量+1)
}
流程:
- 申请空间:通过
_spacesem.P()
等待缓冲区有空位。 - 生产数据:在锁保护下写入数据并更新生产者索引。
- 通知消费者:通过
_datasem.V()
增加可消费数据数量。
4.3.3 Pop(消费者接口)
void Pop(T *out) {_datasem.P(); // 等待可消费数据(信号量-1){LockGuard lockguard(_c_lock); // 加消费者锁*out = _ring[_c_step]; // 读取数据_c_step = (_c_step + 1) % _cap; // 环形移动}_spacesem.V(); // 增加可用空间(信号量+1)
}
流程:
- 申请数据:通过
_datasem.P()
等待缓冲区有数据。 - 消费数据:在锁保护下读取数据并更新消费者索引。
- 通知生产者:通过
_spacesem.V()
增加可用空间数量。
4.4 同步机制
4.4.1 信号量控制
- 生产者阻塞条件:
_spacesem
为0时(缓冲区满)。 - 消费者阻塞条件:
_datasem
为0时(缓冲区空)。
4.4.2 互斥锁保护
4.5 整体代码
#include "Cond.hpp"
#include "Mutex.hpp"
#include "Sem.hpp"#include <vector>
#include <pthread.h>namespace RingBufferModule{using namespace LockModule;using namespace CondModule;using namespace SemModule;template<typename T>class RingBuffer{public:RingBuffer(int cap): _ring(cap), // 初始化缓冲区容量_cap(cap), // 记录总容量_p_step(0), // 生产者起始位置_c_step(0), // 消费者起始位置_datasem(0), // 初始无可消费数据_spacesem(cap) // 初始空间=总容量{}// 生产者接口void Equeue(const T &in) {_spacesem.P(); // 等待可用空间(信号量-1){LockGuard lockguard(_p_lock); // 加生产者锁_ring[_p_step] = in; // 写入数据_p_step = (_p_step + 1) % _cap; // 环形移动}_datasem.V(); // 增加可消费数据(信号量+1)}// 消费者接口void Pop(T *out) {_datasem.P(); // 等待可消费数据(信号量-1){LockGuard lockguard(_c_lock); // 加消费者锁*out = _ring[_c_step]; // 读取数据_c_step = (_c_step + 1) % _cap; // 环形移动}_spacesem.V(); // 增加可用空间(信号量+1)}// 析构函数~RingBuffer(){}private:std::vector<T> _ring; // 环,临界资源int _cap; // 环的容量 int _p_step; // 生产者指针位置int _c_step; // 消费者指针位置Mutex _p_lock; // 生产者锁Mutex _c_lock; // 消费者锁Sem _datasem; // 数据信号量Sem _spacesem; // 空间信号量};
}
4.6 测试代码
#include "RingBuffer.hpp"
#include <pthread.h>
#include <unistd.h>
#include <ctime>using namespace RingBufferModule;void *Consumer(void *args)
{RingBuffer<int> *ring_buffer = static_cast<RingBuffer<int> *>(args);while(true){sleep(1);// sleep(1);// 1. 消费数据int data;ring_buffer->Pop(&data);// 2. 处理:花时间std::cout << "消费了一个数据: " << data << std::endl;}
}void *Productor(void *args)
{RingBuffer<int> *ring_buffer = static_cast<RingBuffer<int> *>(args);int data = 0;while (true){// 1. 获取数据:花时间// sleep(1);// 2. 生产数据ring_buffer->Equeue(data);std::cout << "生产了一个数据: " << data << std::endl;data++;}
}int main()
{RingBuffer<int> *ring_buffer = new RingBuffer<int>(5); // 共享资源 -> 临界资源// 单生产,单消费pthread_t c1, p1, c2,c3,p2;pthread_create(&c1, nullptr, Consumer, ring_buffer);pthread_create(&c2, nullptr, Consumer, ring_buffer);pthread_create(&c3, nullptr, Consumer, ring_buffer);pthread_create(&p1, nullptr, Productor, ring_buffer);pthread_create(&p2, nullptr, Productor, ring_buffer);pthread_join(c1, nullptr);pthread_join(c2, nullptr);pthread_join(c3, nullptr);pthread_join(p1, nullptr);pthread_join(p2, nullptr);delete ring_buffer;return 0;
}
👥总结
本篇博文对 【Linux】条件变量封装类及环形队列的实现 做了一个较为详细的介绍,不知道对你有没有帮助呢
觉得博主写得还不错的三连支持下吧!会继续努力的~
相关文章:
【Linux】条件变量封装类及环形队列的实现
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
wsl2 配置ubuntu 固定ip
提示:环境搭建 文章目录 前言一、安装sshd 服务1. ubuntu 子系统安装 openssh-server2.配置sshd 开启密码链接3.配置sshd 服务开机启动 二、配置固定IP1 查看i2 查看路由3 查看wsl虚拟网卡4 配置wsl 子系统网卡4 设置生效 三、问题1. ssh 无法远程 前言 提示&#…...
电机控制学习路线
一、基础理论准备阶段 电路与电子技术 电路分析基础(基尔霍夫定律、动态电路分析) 模拟电子技术(放大器、滤波电路、功率器件) 数字电子技术(逻辑电路、微控制器基础) 数学工具 线性代数(矩…...
Sensodrive力控关节模组SensoJoint:TÜV安全认证助力机器人开发
在机器人技术领域,安全性和开发效率是行业关注的重点。SensoDrive的SensoJoint 机器人力控关节模组,凭借其可靠的安全性能和高效的开发优势,正在为机器人开发提供有力支持。 2025年3月31日,SensoDrive的 SensoJoint 力控关节模组获…...
【橘子大模型】Runnable和Chain以及串行和并行
一、Runnable 前面我们实现了一些关于如何和大模型进行交互的操作。那么我们此时来回顾一下我们当前进行的结构。 我们已经很清楚这些操作的具体含义了,所以我这里就不在多介绍了。我们来看其中的几个点 1、用户那边就是客户,没啥说的。 2、langchain&…...
数据结构 -- 图的存储
图的存储 邻接矩阵法 邻接矩阵存储不带权图 0 - 表示两个顶点不邻接 1 - 表示两个顶点邻接 在无向图中,每条边在矩阵中对应两个1 在有向图中,每条边在矩阵中对应一个1 //不带权图的邻接矩阵存储 #define MaxVertexNum 100 //顶点数目的最大值 typed…...
基于大模型预测不稳定性心绞痛的多维度研究与应用
目录 一、引言 1.1 研究背景与意义 1.2 研究目的 1.3 国内外研究现状 二、不稳定性心绞痛概述 2.1 定义与分类 2.2 发病机制 2.3 临床表现 三、大模型技术原理与应用基础 3.1 大模型介绍 3.2 在医疗领域的应用现状 3.3 用于不稳定性心绞痛预测的可行性 四、术前预…...
【Java集合】LinkedList源码深度分析
参考笔记:java LinkedList 源码分析(通俗易懂)_linkedlist源码分析-CSDN博客 目录 1.前言 2.LinkedList简介 3.LinkedList的底层实现 4.LinkedList 与 ArrayList 的对比 4.1 如何选择 4.2 对比图 5.LinkedList 源码Debug 5.1 add(E e) ÿ…...
Java 大视界 -- Java 大数据在智能供应链库存优化与成本控制中的应用策略(172)
💖亲爱的朋友们,热烈欢迎来到 青云交的博客!能与诸位在此相逢,我倍感荣幸。在这飞速更迭的时代,我们都渴望一方心灵净土,而 我的博客 正是这样温暖的所在。这里为你呈上趣味与实用兼具的知识,也…...
高并发系统架构设计核心要点的结构化提炼【大模型总结】
以下是对高并发系统架构设计核心要点的结构化提炼,结合技术深度与实践视角,以清晰的层次呈现关键策略与实现路径: 一、核心理念重塑 1. 容错优先思维 设计哲学:从"零故障"转向"可恢复性"设计,接…...
【C#深度学习之路】如何使用C#实现Stable Diffusion的文生图功能
【C#深度学习之路】如何使用C#实现Stable Diffusion的文生图功能 项目背景项目实现写在最后项目下载链接 本文为原创文章,若需要转载,请注明出处。 原文地址:https://blog.csdn.net/qq_30270773/article/details/147002073 项目对应的Github地…...
k8s的pod的概述和配置
概念 Pod 容器组 是一个k8s中一个抽象的概念,用于存放一组 container(可包含一个或多个 container 容器,即图上正方体),以及这些 container (容器)的一些共享资源。这些资源包括: 共享存储&…...
RTOS任务句柄的作用
任务句柄(Task Handle)在 FreeRTOS 中的作用详解 任务句柄(TaskHandle_t)是 FreeRTOS 中用于 唯一标识和管理任务 的核心机制,本质是一个指向任务控制块(TCB)的指针。说明即便创建的任务名相同,但对应的任务句柄一定是不同。 它在任务管理、通信、调试中起到关键作用,…...
OpenVLA-OFT——微调VLA的三大关键设计:并行解码、动作分块、连续动作表示以及L1回归目标
前言 25年3.26日,这是一个值得纪念的日子,这一天,我司「七月在线」的定位正式升级为了:具身智能的场景落地与定制开发商 ,后续则从定制开发 逐步过渡到 标准产品化 比如25年q2起,在定制开发之外࿰…...
LocaDate、LocalTime、LocalDateTime
Java8的时间处理 Java的时间处理在早期版本中存在诸多问题(如 java.util.Date 和 java.util.Calendar 的混乱设计),但Java8引入了引入了全新的 java.time包(基于JSR 310),提供了更清晰、线程安全且强大的时…...
哈密尔顿路径(Hamiltonian Path)及相关算法题目
哈密尔顿路径要求访问图中每个顶点恰好一次,通常用于解决旅行商问题(TSP)或状态压缩DP问题。 哈密尔顿路径(Hamiltonian Path)是指在一个图中经过每个顶点恰好一次的路径。如果这条路径的起点和终点相同(即…...
突破传统限制!全新端到端开放词汇多目标跟踪框架OVTR,开启视觉追踪新纪元
在自动驾驶和智能监控等场景中,多目标跟踪(MOT)技术需要应对现实世界中层出不穷的新物体类别。传统方法依赖预定义类别,面对“无人机配件”“新型宠物”等未知目标时往往失效。上海人工智能实验室团队提出的OVTR(Open-…...
Springboot + Vue + WebSocket + Notification实现消息推送功能
实现功能 基于Springboot与Vue架构,首先使用Websocket实现频道订阅,在实现点对点与群发功能后,在前端调用windows自带的消息通知,实现推送功能。 开发环境 Springboot 2.6.7vue 2.6.11socket-client 1.0.0 准备工作 在 Vue.js…...
Linux内核物理内存组织结构
一、系统调用sys_mmap 系统调用mmap用来创建内存映射,把创建内存映射主要的工作委托给do_mmap函数,内核源码文件处理:mm/mmap.c 二、系统调用sys_munmap 1、vma find_vma (mm, start); // 根据起始地址找到要删除的第一个虚拟内存区域 vma 2…...
Redis高级技能进阶
什么是事务的ACID 事务是由一系列对系统中数据进行访问或更新的操作组成的程序执行逻辑单元。这些操作要么都执行,要么都不执行。 为了保证数据库的一致性,在事务处理之前和之后,都应该遵循某些规则,也就是大家耳熟能详的ACID。 …...
PCB设计基础:面向嵌入式工程师的系统性指南
嵌入式系统的性能、稳定性和可靠性,很大程度上依赖于电路硬件的设计质量。在硬件设计中,PCB(Printed Circuit Board)设计是连接系统功能与实际运行的关键一环。本文将从嵌入式工程师的视角,系统性地介绍PCB设计的关键基…...
aspark 配置2
编写Hadoop集群启停脚本 1.建立新文件,编写脚本程序 在hadoop101中操作,在/root/bin下新建文件:myhadoop,输入如下内容: 2.分发执行权限 保存后退出,然后赋予脚本执行权限 [roothadoop101 ~]$ chmod x /r…...
【统计方法】LASSO筛变量
启 比较原始做LASSO包是library(glmnet) 若目标是纯 LASSO 分析,alpha 必须设为 1 标准化数据:LASSO 对特征的尺度敏感,需对数据进行标准化(均值为0,方差为1)。 cv.glmnet获得的lambda.m…...
拥抱健康生活,书写养生新篇
在快节奏的现代生活中,健康愈发成为人们关注的焦点。践行健康养生,并非是一种选择,而是我们对自己和家人应尽的责任。掌握正确的养生之道,不仅能提升生活品质,更能让生命焕发出新的活力。 合理饮食是健康的基石。一…...
Shiro学习(五):Shiro对权限的缓存
一、问题描述 由前边的学习中了解,用户的角色权限一般存储在数据库中,每次进行权限校验时都要从 数据库查询用户的角色权限信息;对数据库来说这样频繁的查询压力太大了,也影响程序的 性能。 Shiro 中执行权限角色校验时࿰…...
QGIS实战系列(六):进阶应用篇——Python 脚本自动化与三维可视化
欢迎来到“QGIS实战系列”的第六期!在前几期中,我们从基础操作到插件应用逐步提升了 QGIS 技能。这一篇,我们将迈入进阶领域,探索如何用 Python 脚本实现自动化,以及如何创建三维可视化效果,让你的 GIS 项目更高效、更立体。 第一步:Python 脚本自动化 QGIS 内置了 Py…...
redis-cpp-cpp如何使用lua脚本
1.前言 我今天要在项目中使用lua脚本,结果搞半天都没有弄明白这个函数怎么调用,而且也似乎很少有redis相关的博客介绍,ai也回答的不准确! 2.正文 今天用一个例子演示一下 下面是lua脚本 const std::string LuaScript R"…...
C# Winform 入门(6)之不同类之间的值传递
承接上一个教程,利用委托事件来进行值传递 声明变量 public static double plx, ply,plxx,plyy;声明委托、事件 //声明委托 //事件 public delegate void transferDistance(double dis); public static transferDistance doTransfer; 直接读取form1中的变量 publ…...
JWT 秘钥的作用机制
JWT 秘钥的作用并不是给前端使用的,而是用于后端服务器内部的一个重要安全机制。 JWT 秘钥的作用 签名与验证: 秘钥主要用于对 JWT(JSON Web Token)进行签名和验证后端使用这个秘钥对令牌进行签名,确保令牌的完整性…...
sun.misc.BASE64Encoder 和 sun.misc.BASE64Decoder包
1. 在将别人的项目导入eclipse之后,出现了"sun.misc.BASE64Encoder找不到jar"的错误,我解决的办法是:右键项目》属性》Java Build Path》jre System Library 》access rules 》resolution选择accessible,下面填上**点击确定即可࿰…...
Java面试黄金宝典34
1. 主键索引底层的实现原理 定义 主键索引是数据库中用于唯一标识表中每一行记录的索引,常见的底层实现是 B 树结构。B 树是一种平衡的多路搜索树,由内部节点和叶子节点组成。内部节点只存储索引键和指向下一层节点的指针,不存储实际数据&am…...
计算机系统---CPU
定义与功能 中央处理器(Central Processing Unit,CPU),是电子计算机的主要设备之一,是计算机的核心部件。CPU是计算机的运算核心和控制核心,负责执行计算机程序中的指令,进行算术运算、逻辑运算…...
AWS云安全基线:构建企业级安全防护体系的完整指南
1. 引言 随着越来越多的企业将其业务和数据迁移到云端,云安全已成为一个不容忽视的关键议题。AWS作为全球领先的云服务提供商,提供了丰富的安全工具和最佳实践。本文将深入探讨如何构建一个全面的AWS云安全基线,以确保您的企业在云环境中的安全性。 2. AWS共享责任模型 在深…...
(三十三)Dart 中使用 Pub 包管理系统与 HTTP 请求教程
Dart 中使用 Pub 包管理系统与 HTTP 请求教程 Pub 包管理系统简介 Pub 是 Dart 和 Flutter 的包管理系统,用于管理项目的依赖。通过 Pub,开发者可以轻松地添加、更新和管理第三方库。 使用 Pub 包管理系统 1. 找到需要的库 访问以下网址,…...
如何实现单例模式?
一、模式定义与核心价值 单例模式(Singleton Pattern)是一种创建型设计模式,保证一个类仅有一个实例,并提供全局访问点。其核心价值在于: 资源控制:避免重复创建消耗性资源(如数据库连…...
【51单片机】2-4【I/O口】震动传感器控制继电器
1.硬件 51最小系统继电器模块震动传感器模块 2.软件 #include "reg52.h"sbit vibrate P3^3;//震动传感器DO接到P3.3口 sbit switcher P1^1;//继电器控制端IN接到P1.1void Delay2000ms() //11.0592MHz {unsigned char i, j, k;// _nop_();i 15;j 2;k 235;do{…...
正点原子 迷你 miniSTM32用ST link烧录后程序不运行(已解决)
情况,在程序和配置都没有问题时检查 烧录使用ST linkv2 烧录后有时程序可行,有时不可行 解决方法 加USB供电配合SW烧录 建议直接用USB转串口烧录 不推荐JLINK供电,也不推荐ST linkv2供电...
如何确保MQ消息队列不丢失:Java实现与流程分析
前言 在分布式系统中,消息队列(Message Queue, MQ)是核心组件之一,用于解耦系统、异步处理和削峰填谷。然而,消息的可靠性传递是使用MQ时需要重点考虑的问题。如果消息在传输过程中丢失,可能会导致数据不一…...
Pascal语言的系统监控
Pascal语言的系统监控 引言 在现代计算机系统中,系统监控是确保计算机平稳运行的重要组成部分。无论是个人计算机还是大型服务器,监控系统的性能、资源使用及状态,都是提高系统效率、及时发现问题的关键。Pascal语言作为一种结构化编程语言…...
6.0 使用Qt+ OpenCV+Python加载图片
本例作为python图像处理的入门课程1,使用Qt+ OpenCV+Python加载图片。 主要有如下几个地方需要注意: 1. OpenCV 默认使用 BGR 格式,而 Qt 使用 RGB。显示前需要转换:cv2.cvtColor(img, cv2.COLOR_BGR2RGB),一般使用某个QLabel控件进行显示。 pic = cv2.cvtColor(pic, cv2.C…...
低成本训练垂直领域文娱大模型的技术路径
标题:低成本训练垂直领域文娱大模型的技术路径 内容:1.摘要 在文娱产业快速发展且对智能化需求日益增长的背景下,为降低垂直领域文娱大模型的训练成本,本研究旨在探索低成本训练的有效技术路径。采用对现有开源模型进行微调、利用轻量化模型架构以及优化…...
音视频入门基础:RTP专题(21)——使用Wireshark分析海康网络摄像机RTSP的RTP流
一、引言 使用vlc等播放器可以播放海康网络摄像机的RTSP流: 网络摄像机的RTSP流中,RTSP主要用于控制媒体流的传输,如播放、暂停、停止等操作。RTSP本身并不用于转送媒体流数据,而是会通过PLAY方法使用RTP来传输实际的音视频数据。…...
【Java网络编程详解】
文章目录 前言一、网络编程基础知识1. 什么是网络编程? 二、Java网络编程核心类三、TCP编程实现1. TCP通信原理2. TCP服务器端示例3. TCP客户端示例 四、UDP编程实现1. UDP通信原理2. UDP服务器端示例3. UDP客户端示例 五、使用HttpURLConnection发送HTTP请求1. GET…...
DuckDB系列教程:如何分析Parquet文件
Parquet 是一种强大的、基于列的存储格式,适用于实现更快捷和更高效的数据分析。您可以使用 DuckDB 这种内存型分析数据库来处理 Parquet 文件并运行查询以对其进行分析。 在这篇文章中,我们将逐步介绍如何使用 DuckDB 对存储在 Parquet 文件中的餐厅订单…...
uniapp的v-for不显示或者swiper-item的不显示
今天开发的时候碰见一个问题,在布局的时候发现v-for遍历的时候不显示内容 H5是正常的 但是在小程序就是不显示 最后排查的原因是同一个组件 swiper-item的 v-for不能用相同的名称 比如 <swiper-item v-for"i in 3" :key"i"><image …...
解决LeetCode“使括号有效的最少添加”问题
目录 问题描述 解题思路 复杂度分析 示例分析 暴力替换“不讲码德” 总结 问题描述 给定一个仅由 ( 和 ) 组成的字符串 s,我们需要通过添加最少数量的括号(( 或 ))使得字符串有效。有效字符串需满足: 空字符串是有效的。 …...
黑马点评_知识点
将手机验证码保存到HttpSession中进行验证(感觉已经过时) Controller中的参数有HttpSession,存验证码session.setAttribute(SystemConstants.VERIFY_CODE, code); 其他的都是逻辑代码 Cookie的缺点 什么是Session集群共享问题? …...
2025年渗透测试面试题总结-某腾讯-玄武实验室扩展(题目+回答)
网络安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 某腾讯-玄武实验室扩展 一、Web安全基础原理与关联漏洞 1.1 CSRF攻击原理深度解析 1.2 反序列化漏洞…...
管理系统 UI 设计:提升企业办公效率的关键
一、管理系统UI设计的基本原则 管理系统UI设计应遵循一系列基本原则,以确保界面友好、操作便捷、信息直观。这些原则包括: 简洁性:界面应去除冗余元素,保持简洁明了,避免用户迷失在复杂界面中。一致性:界…...