浅谈0/1切换
前言:
做过GUI开发的同学, 都知晓双缓存机制. 其过程为先把所有的场景和实体对象画到一个备份canvas, 然后再把备份canvas的内容整个填充真正的画板canvas中. 如果不采用双缓存机制, 你的画面有可能会出现闪烁和抖动.
究其原因是整个绘制过程, 包含清屏, 绘制场景和各个实体. 其耗时远远大于单个canvas的复制. 进而导致CPU写canvas的速率小于LCD读取canvas的速率. 这样就出现闪烁的现象了.
在后台服务中, 也会遇到类似的情形: 当数据/资源需要更新时, 采用直接增量更新的方式代价大(耗时长, 阻塞服务可用/实时响应), 由此引入back buffer,做0/1切换.
本文以"配置文件热载更新"为例, 着重介绍0/1切换的思路和优化技巧.
热载更新:
以往更新配置时, 往往需要重启服务进程. 为了提高服务的可用性, 更方便运维.
采取的改进方式是:
1) 引入配置中心服务(ConfigServer)
把模块的配置文件搁置在ConfigServer中, 具体模块从ConfigServer中获取(拉起/通知).
2) 监控本地配置文件变更
进程模块通过定期轮询/事件触发的方式, 感知配置文件是否发生变化, 若发生变化, 则重新载入.
但无论采用何种方式, 势必存在切换过程.
切换特点:
把切换的双方定义为前端和后端, 前端资源往往被N个线程访问(静态只读), 后端资源往往是一个线程更新写. 于是就形成了一个N读1写的格局.
具体在c/c++实现时, 切换过程往往就是一个指针的重新赋值, 十分简单.
但问题也就隐藏在这了, 在切换后的旧资源销毁过程中, 存在多线程的竞态冲突风险.
有人可能会提议, 如果对资源的访问和资源的切换加相同的锁保护, 就没有这个问题. 但在低频率切换的场景下, 加锁带来的性能损失, 有些得不偿失.
无锁0/1切换:
是否存在无锁的切换方式呢?
1). 延迟销毁
工作线程持有并访问旧资源句柄时间不长, 可以设定一个时间窗口, 该时间窗口内属于保护期, 禁止对旧资源进行销毁.
注: 在绝大多数场景下, 该方案满足条件. 只是理论上, 不排除低概率事件.
2). 带引用计数的智能指针切换
我们借助boost的shared_ptr来构建切换的小例子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #include <boost/shared_ptr.hpp> #include <stdint.h> #include <stdio.h> class Config { }; class DataCenter { public : DataCenter() { } void init() { active_idx = 0; switchover[active_idx].reset( new Config()); } // *) 切换函数, 由更新线程调用 void swith() { uint32_t unactive_idx = (active_idx == 0) ? 1 : 0; uint32_t old_active_idx = active_idx; // *) 新资源ready switchover[unactive_idx].reset( new Config()); // *) 正式切换 active_idx = unactive_idx; // *) 旧资源reset, 引入计数减一 switchover[old_active_idx].reset(); } // *) 访问资源, 由前端线程调用 boost::shared_ptr<Config> getConfig() { return switchover[active_idx]; } private : volatile uint32_t active_idx; // *) 切换数组 boost::shared_ptr<Config> switchover[2]; }; |
巧用boost::shared_ptr内部有个原子计数器和代理指针, 借助RAII的思想完美的实现了无引用时的自动清理工作. 也避免了上述的竞态冲突.
总结:
在服务模块中的0/1切换有很多, 这边简述了下解决方案, 没有细致展开, 权当个人的学习笔记.
写在最后:
如果你觉得这篇文章对你有帮助, 请小小打赏下. 其实我想试试, 看看写博客能否给自己带来一点小小的收益. 无论多少, 都是对楼主一种由衷的肯定.
posted on 2015-04-30 12:46 mumuxinfei 阅读(896) 评论(2) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
2014-04-30 书评<<剑指offer 名企面试官精讲典型编程题>>
2014-04-30 Hive cli源码阅读和梳理