C++操作redis(实现连接池、分布式锁)
文章目录
- Redis连接池
- 编译项目
- 整体架构
- 使用
- 分布式锁
- 总结
Redis连接池
封装hiredis的一些基本操作,redishelper类提供包含连接,放回,存取键,push,pop,执行redis语句和执行lua脚本的函数,连接池是类模板,传入相应helper类即可实现多种连接池,后续实现mysql连接池。
编译项目
- 安装hiredis,解压文件中hiredis.tar(后续对源码进行了改动,文件中是改后的)
tar -xvf hiredis.tar
cd hiredis/
make
make install # 权限不足加上sudo
- 删除之前的CMakeCache.txt
cd ConnPool/
rm CMakeCache.txt
- 重新cmake和make
cmake .
make -j4
- 后续引入头文件SimConnPool.h即可使用,简单应用见tests文件
整体架构
- RedisHelper:redis相关操作,创建一个连接时构造函数不做任何事,在connection函数时才真正建立一条连接,每条连接都包含一个指向连接池的指针,为了实现放回操作,基础实现依赖hiredis库中的redisCommand函数
- ConnPool :连接池模板,初始化时构造函数不做任何操作,在连接池connection时才执行init函数完成每一个连接的初始化,并且依次调用每条连接的connection函数
- Singleton:单例模板,包装ConnPool类,变成单例对象
使用
static SimpleConnPool::redisPool* pool = SimpleConnPool::redisConnPoolMgr::GetInstance(); // 获取一个连接池单例对象,默认5个连接
pool->connection("127.0.0.1", 6000); // 连接池内连接上redis,入参:ip、端口号、密码默认为空
SimpleConnPool::redisPool::connPtr conn = pool->get(); // 取出一条连接
// TODO
conn->connBack(); // 放回连接
分布式锁
当多线程并发访问数据库中某个资源时,可能同一时间返回都取到了旧值,并且对旧值进行变更,这样会造成逻辑上的混淆。比如在电商场景,库存这个变量,当多个用户进行抢购的时候,首先判断库存然后库存减一,若不加锁,库存为1的时候,可能多个用户获取库存判断时都拿到了1,最后都进行库存减一,可能就出现负数了。
在分布式系统环境下,一个方法在同一时间只能被一个机器的一个线程执行
高可用的获取锁与释放锁
具备可重入特性(可理解为重新进入,由多于一个任务并发使用,而不必担心数据错误)
具备锁失效机制,即自动解锁,防止死锁
加锁:
实际是,对一个键进行赋值,借助set key val NX PX timeout 语句实现,NX表示若键存在返回nil,不存在则赋值,当多线程运行到lock时,只有第一个执行语句的线程可以跳出,继续执行,其余线程都需要阻塞在lock内部。
设置超时时间为了保证不会因为加锁线程挂掉而导致死锁的情况。
/* 加锁逻辑:在不存在键时设置键 并同时设置超时时间 保证原子性set key value NX PX timeout默认10秒返回该线程拿到锁生成的值,后续解锁比较,不能因为挂机或网络原因解锁别的线程锁分布式锁的键为:redis.lock 值为:当前时间戳 nsec*/
std::string lock(uint64_t timeout = 30000) {while(1) {struct timespec time = {0, 0};clock_gettime(CLOCK_REALTIME, &time);std::string uuid = std::to_string(time.tv_nsec);std::string cmd = "set redis.lock " + uuid + " NX PX " + std::to_string(timeout);std::string flag;RedisState sta;{MutexType::Lock lock(m_mutex);sta = execute(cmd, &flag);}if(sta == RedisState::M_REDIS_OK) {std::cout << "get redis.lock!" << std::endl;return uuid;}}
}
解锁:
需要取值、判断、删除三个操作,因此使用lua脚本来保证原子性,判断是为了保证不会删除其余线程所创建的锁。
/*解锁逻辑:获取锁,判断锁,删除锁为了保证原子性,使用lua脚本来完成三个操作redis使用eval "xxxx" keys数量 key1 key2 num1 num2 */
void unlock(const std::string& uuid) {std::string cmd = "eval \"if redis.call('get',KEYS[1]) == ARGV[1] then return redis.call('del',KEYS[1]) else return 0 end\" 1 redis.lock " + uuid;int flag;RedisState sta = executeLua(cmd.c_str(), &flag);if(sta == RedisState::M_REDIS_OK && flag > 0) {std::cout << "获取到锁并解锁" << std::endl;}else {std::cout << "未获取到锁 errstr: " << m_error_msg << std::endl;}return ;
}
总结
基于hiredis,只需要引入头文件即可使用,简单方便,复杂语句使用execute函数直接执行,但是需要根据redis客户端返回值,传入该函数第二个参数(set,get返回ok就传string,del返回1或0就传int)
为了可以执行lua脚本,对hiredis中源码进行了改动,原先是以空格来分割命令的,但是lua脚本需要return时肯定包含空格,需要更改分割规则,增加以双引号分割,详见(hiredis中lua脚本调用_hiredis lua_suhiymof的博客-CSDN博客)
std::string cmd = "EVAL \"redis.call('SET', KEYS[1], ARGV[1]) local result = redis.call('get',KEYS[1]) return result\" 1 foo1 bar1";
std::string flag; // set get为string类型,del为int类型,看redis客户端返回的类型设置
conn->executeLua(cmd.c_str(), &flag);
std::cout << "lua执行结果:" << flag << std::endl;
帮助大家熟悉C++和redis的基本操作,使用lua脚本实现了简单的分布式锁,可以多线程的访问数据库中某个变量
还缺少健康检测,自动扩缩容等实现,大家有需要可以继续开发
整体项目地址 供大家学习使用,如果有帮助请多点点star
相关文章:
C++操作redis(实现连接池、分布式锁)
文章目录Redis连接池编译项目整体架构使用分布式锁总结Redis连接池 封装hiredis的一些基本操作,redishelper类提供包含连接,放回,存取键,push,pop,执行redis语句和执行lua脚本的函数,连接池是类…...
硬件基础专题-01电阻篇
目录 课程链接 学习目的 电阻 电阻理论讲解 电阻定义 欧姆定律 电阻单位换算 电阻选型考虑 安装方式 常见电阻值 各种贴片电阻的读取方式 确定电阻值的方法 电阻数据手册 电阻测量 电阻的产品应用 零欧姆电阻 热敏电阻 光敏电阻 课程链接 视频专辑 - 硬件…...
【JAVA程序设计】(C00112)基于Springboot+Thymeleaf的在线购物商城——有文档
基于SpringbootThymeleaf的在线购物商城——有文档项目简介项目获取开发环境项目技术运行截图运行视频项目简介 基于Springbootthymeleaf框架的在线购物商城系统,本系统共分为二个角色:管理员和用户 管理员角色包含以下功能: 商品管理、商品…...
shell基础(5)算数计算:运算语法、自增自减
文章目录1. shell算数运算的特点2. 运算符一览3. 运算语法3.1 整形运算3.2. 小数运算 ing4. 自增自减4.1. a与a4.2. 自加1. shell算数运算的特点 Shell 和其它编程语言不同,Shell 不能直接进行算数运算,必须使用数学计算命令。Shell只支持整数运算&#…...
virtio设备input节点
注册virtio_input_node节点,节点类型为VLIB_NODE_TYPE_INPUT。 VLIB_REGISTER_NODE (virtio_input_node) {.name "virtio-input",.sibling_of "device-input",.format_trace format_virtio_input_trace,.flags VLIB_NODE_FLAG_TRACE_SUPP…...
《计算机网络:自顶向下方法》学习笔记——第一章:计算机网络和因特网
计网 第一章 计算机网络和因特网 1.1 什么是因特网 回答这个问题有两种方式 其一,我们能够描述因特网的具体构成,即构成因特网的基本硬件和软件组件;其二,我们能够根据为分布式应用提供服务的联网基础设施来描述因特网。 1.1.…...
PDF 解析格式化输出 API 数据接口
PDF 解析格式化输出 API 数据接口 支持输出 TEXT HTML XML TAG,多种格式输出,超精准识别率。 1. 产品功能 通用的识别接口, 支持标准 PDF 文件解析;多种格式输出,支持 TEXT HTML XML TAG;HTML 包含完美排…...
RL笔记:基于策略迭代求CliffWaking-v0最优解(python实现)
目录 1. 概要 2. 实现 3. 运行结果 1. 概要 CliffWalking-v0是gym库中的一个例子[1],是从Sutton-RLbook-2020的Example6.6改编而来。不过本文不是关于gym中的CliffWalking-v0如何玩的,而是关于基于策略迭代求该问题最优解的实现例。 CliffWalking-v0的…...
350. 两个数组的交集 II
两个数组的交集 II 给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结…...
Android仿微信选择图片
效果展示首先先添加用到的权限<uses-permission android:name"android.permission.INTERNET" /><!--获取手机存储卡权限--><uses-permission android:name"android.permission.READ_EXTERNAL_STORAGE"/><uses-permission android:nam…...
python+嵌入式——串口通信篇(收发解包)
目录前言安装pyserialpyserial大致概括整体流程硬件连接例子(简单版)详细使用serial初始化参数发包收包收包检查包并解包python struct模块结语前言 这几年,自己也做了一些嵌入式机器人。在整个开发的过程中,调通信通常会花费一段比较长的时间ÿ…...
剖析G1 垃圾回收器
简单回顾 在Java当中,程序员在编写代码的时候只需要创建对象,从来不需要考虑将对象进行释放,这是因为Java中对象的垃圾回收全部由JVM替你完成了(所有的岁月静好都不过是有人替你负重前行)。 而JVM的垃圾回收由垃圾回收器来负责,在…...
如何打造一款专属于自己的高逼格电脑桌面
作为一名电脑重度使用者,你是否拥有一款属于你自己的高逼格电脑桌面呢?你是不是也像大多数同学一样,会把所有的内容全部都堆积到电脑桌面,不仅找东西困难,由于桌面内容太多还会导致C盘空间不足,影响电脑的反…...
【C++】string的使用及其模拟实现
文章目录1. STL的介绍1.1 STL的六大组件1.2 STL的版本1.3 STL的缺陷2. string的使用2.1 为什么要学习string类?2.2 常见构造2.3 Iterator迭代器2.4 Capacity2.5 Modifiers2.6 String operations3. string的模拟实现3.1 构造函数3.2 拷贝构造函数3.3 赋值运算符重载和…...
怀念在青鸟的日子
时间过的可真快,一转眼来到了2023年!我初中上完就没有在念,下了学门步入社会,那时的我一片迷茫,不知道该去干什 么,父母说要不去学挖掘机、理发、修车...我思考再三,一个都没有我喜欢的…...
学习记录---Python内置类型
文章目录字符串split()列表常见操作列表相减字典创建普通创建eval(s)添加或更新元素d[t] 1d.update({c: 3}){**d1, **d2} **字典解包装运算符删除元素 d.pop(c)属性d.items()d.keys()d.values()访问元素d[Name]d.get(score)遍历字典for key in dictfor key, values in dict.it…...
Python笔记 -- 列表
文章目录1、列表简介2、修改、添加、删除元素2.1、添加2.2、删除3、排序、倒序4、遍历列表5、创建数值列表6、列表切片7、列表复制8、元组1、列表简介 在Python中用方括号[]表示列表,用逗号隔开表示其元素 通过索引访问列表 names [aa,bb,cc,dd]print(names[0]) …...
谈谈UVM中的uvm_info打印
uvm_info宏的定义如下: define uvm_info(ID,MSG,VERBOSITY) \begin \if (uvm_report_enabled(VERBOSITY,UVM_INFO,ID)) \uvm_report_info (ID, MSG, VERBOSITY, uvm_file, uvm_line); \end 从这里可以看出uvm_info由两部分组成:uvm_report_enabled(VER…...
矩阵理论1 集合上的等价关系(equivalence relations on a set S)
定义 对于一个集合S, 如果集合E⊂SS\mathcal{E} \subset S\times SE⊂SS满足以下条件 自反性: 对于∀s∈S,都有(s,s)∈E\forall s\in S, 都有 (s, s) \in \mathcal{E}∀s∈S,都有(s,s)∈E对称性: (s,t)∈E⇔(t,s)∈E(s,t) \in \mathcal{E} \Leftrightarrow (t,s)\in \mathcal…...
【网络监控】Zabbix详细安装部署(最全)
文章目录Zabbix详细安装部署环境准备安装依赖组件访问初始化配置Zabbix详细安装部署 Zabbix 是一个高度集成的网络监控解决方案,可以提供企业级的开源分布式监控解决方案,由一个国外的团队持续维护更新,软件可以自由下载使用,运作…...
Python|GIF 解析与构建(5):手搓截屏和帧率控制
目录 Python|GIF 解析与构建(5):手搓截屏和帧率控制 一、引言 二、技术实现:手搓截屏模块 2.1 核心原理 2.2 代码解析:ScreenshotData类 2.2.1 截图函数:capture_screen 三、技术实现&…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
TDengine 快速体验(Docker 镜像方式)
简介 TDengine 可以通过安装包、Docker 镜像 及云服务快速体验 TDengine 的功能,本节首先介绍如何通过 Docker 快速体验 TDengine,然后介绍如何在 Docker 环境下体验 TDengine 的写入和查询功能。如果你不熟悉 Docker,请使用 安装包的方式快…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
对WWDC 2025 Keynote 内容的预测
借助我们以往对苹果公司发展路径的深入研究经验,以及大语言模型的分析能力,我们系统梳理了多年来苹果 WWDC 主题演讲的规律。在 WWDC 2025 即将揭幕之际,我们让 ChatGPT 对今年的 Keynote 内容进行了一个初步预测,聊作存档。等到明…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...
什么是EULA和DPA
文章目录 EULA(End User License Agreement)DPA(Data Protection Agreement)一、定义与背景二、核心内容三、法律效力与责任四、实际应用与意义 EULA(End User License Agreement) 定义: EULA即…...
Caliper 配置文件解析:config.yaml
Caliper 是一个区块链性能基准测试工具,用于评估不同区块链平台的性能。下面我将详细解释你提供的 fisco-bcos.json 文件结构,并说明它与 config.yaml 文件的关系。 fisco-bcos.json 文件解析 这个文件是针对 FISCO-BCOS 区块链网络的 Caliper 配置文件,主要包含以下几个部…...
基于matlab策略迭代和值迭代法的动态规划
经典的基于策略迭代和值迭代法的动态规划matlab代码,实现机器人的最优运输 Dynamic-Programming-master/Environment.pdf , 104724 Dynamic-Programming-master/README.md , 506 Dynamic-Programming-master/generalizedPolicyIteration.m , 1970 Dynamic-Programm…...
