新闻中心
c++如何安全地发布和订阅事件_c++事件系统与线程安全发布订阅模型实现
答案:C++安全事件系统需用weak_ptr管理生命周期、mutex保护订阅列表,并结合enable_shared_from_this避免悬挂回调。

在C++中实现安全的事件发布与订阅系统,关键在于处理好对象生命周期、线程安全和回调调用的时序问题。一个健壮的事件系统需要支持多线程环境下的发布-订阅模式,同时避免因对象销毁导致的悬空指针或野函数调用。
事件系统的基本结构
一个典型的事件系统包含三个核心部分:事件源(Publisher)
、事件监听器(Subscriber)和事件分发器(EventBus 或 Signal/Slot 机制)。最简单的形式可以通过函数对象(std::function)和连接管理来实现。
使用 std::shared_ptr 和 std::weak_ptr 可以有效管理订阅者的生命周期。当订阅者被销毁时,发布者通过 weak_ptr 检测到该对象已不存在,自动跳过无效回调。
示例结构:- 事件总线维护一个 weak_ptr 的观察者列表
- 每个订阅者注册时传入回调函数和自身 shared_ptr
- 发布事件时遍历列表,仅对 still alive 的 weak_ptr 提升为 shared_ptr 后执行回调
线程安全的订阅与发布
多线程环境下,多个线程可能同时注册、注销或触发事件,必须保证这些操作的原子性。使用 std::mutex 对事件列表的读写进行保护是最直接的方式。
但频繁加锁会影响性能,尤其是高频率事件场景。可以考虑以下优化:
- 使用读写锁(std::shared_mutex)允许多个发布者并发读取订阅列表
- 采用无锁队列缓存事件,在单独线程中派发,减少临界区时间
- 每个线程维护本地事件队列,定期同步到主分发器
注意:回调执行本身通常不应持有锁,避免死锁或阻塞其他订阅者。
美图云修
商业级AI影像处理工具
50
查看详情
避免悬挂回调和析构竞争
常见问题是:订阅者正在被析构,而另一线程正准备调用其回调方法。即使使用 weak_ptr,也不能完全防止 this 指针失效。
解决方案是让订阅者显式取消订阅,或提供一个“关闭”信号机制。更优雅的做法是结合 std::enable_shared_from_this,确保只有当对象仍存活时才允许回调执行。
代码片段示意:
class Subscriber : public std::enable_shared_from_this<Subscriber> {
public:
void onEvent() {
auto self = shared_from_this(); // 只有在 shared_ptr 管理下才安全
// 执行业务逻辑
}
};
发布者调用前需从 weak_ptr.lock() 获取 shared_ptr,失败则说明对象已销毁,跳过即可。
实际可用的设计建议
对于生产级系统,推荐基于信号槽库如 Boost.Signals2,它原生支持线程安全和自动连接管理。若自行实现,应遵循以下原则:
- 所有修改订阅列表的操作必须加锁
- 事件分发尽量异步,避免在发布线程直接调用回调
- 提供连接句柄(connection),允许订阅者主动断开
- 支持自动断开(RAII 风格的 connection 对象)
- 记录并处理回调异常,防止崩溃传播
基本上就这些。设计时优先考虑安全性而非极致性能,再根据实测瓶颈做针对性优化。
以上就是c++++如何安全地发布和订阅事件_c++事件系统与线程安全发布订阅模型实现的详细内容,更多请关注其它相关文章!
# 死锁
# 衡中网站建设
# 重庆企业网站建设维护
# 网站建设系统主题怎么写
# 沛县营销网站推广电话号
# 建网站如何做推广
# 网站文章优化有什么用处
# 做推广网站立联火星赞
# 黄骅seo网站优化
# 大埔县网站建设推广中心
# 河北营销推广价格
# 加锁
# 如何实现
# 跳过
# 回调函数
# 多个
# 客户端
# 多线程
# 美图
# 递归
# 回调
# 有锁
# red
# 无锁
# 常见问题
# c++
# ai
相关栏目:
【
科技资讯46185 】
【
网络学院92790 】
相关推荐:
解决J*aScript中重复选择项的确认对话框显示问题
顺丰快递查单号物流信息 顺丰快递小程序查询入口
怎么去除衣服上的口红印_生活小妙招教你用酒精轻松擦除
Golang如何测试channel通信行为_Golang channel通信测试与分析方法
邮政快递单号查询入口 邮政快递物流信息在线查询入口
Spyder启动失败:字体文件权限拒绝错误解决方案
在python-socketio事件处理器中安全访问Flask应用上下文
如何在J*a中实现统一对象行为接口_项目大型化时的接口规范化
J*a如何使用AtomicInteger控制计数_J*a无锁计数器性能分析
必由学在线入口 必由学网页版快速登录入口
Win11怎么设置鼠标主按键_Win11鼠标左右键功能互换
b站赚钱渠道_b站收益来源
深入理解J*aScript中的B样条曲线与节点向量生成
C++如何实现单例模式_C++设计模式之线程安全的单例写法
c++ 获取系统当前时间 c++时间戳获取方法
汽水音乐网页版使用入口_汽水音乐电脑版播放指南
Win10磁盘清理工具在哪 Win10打开并使用磁盘清理【教程】
文本文档写html代码怎么运行_文本文档html代码运行步骤【教程】
Surface怎么安装系统 微软Surface Pro U盘重装win11教程
怎样更改Windows系统的默认安装路径_避免C盘爆满的终极设置【技巧】
mcjs网页版流畅运行 mcjs低配电脑畅玩入口
Safari怎么安装扩展程序 浏览器插件安装与管理方法【详解】
QQ邮箱官方网站登录入口_QQ邮箱网页版在线使用
163邮箱登录密码 163邮箱忘记密码找回
Shopware订单对象中获取产品自定义字段的正确方法
Selenium Python中处理点击后新窗口加载冻结问题的策略与实践
2026年发布! 美少女养成动作RPG《神剑少女战记》发布实机演示
使用 Pandas 高效处理 .dat 文件:数据清洗与数值计算实战
深入理解Google Cloud Datastore查询:祖先路径与数据一致性
MAC怎么在地图App里使用“四处看看”_MAC体验部分城市的3D实景街景
Golang如何使用new_Go new分配内存机制讲解
没有大陆身份证/银行卡如何实名微信? 亲测有效的几种方法分享
内存疯狂猛猛涨价:主板销量直接腰斩!
C++的std::mdspan是什么_C++23中用于操作多维数组的非拥有视图
age动漫网站入口 age动漫官网直接访问入口
抖音小游戏合成大西瓜免费秒玩入口链接 抖音小游戏热门合集秒玩网站
Composer如何在生产环境安全地执行composer update
如何在CSS中使用visited与link控制链接颜色_visited link伪类配合
QQ邮箱登录首页官网地址2026 QQ邮箱官方网页入口
html两个JS只运行一个怎么办_让双JS在html中都运行方法【技巧】
PHP中SSG-WSG API的AES加密实践:正确使用初始化向量
sublime怎么覆盖插件的默认快捷键_sublime快捷键优先级与设置
顺丰快件物流信息 官方网站查询入口
PowerPoint如何制作滚动字幕结尾彩蛋_PowerPoint路径动画实现平滑滚动字幕效果
steam官方网页快速访问 steam账号注册全流程
QQ邮箱正确登录入口_QQ邮箱官方网站使用地址
漫蛙漫画登录站点 漫蛙2正版漫画快速访问
c++如何实现一个简单的软件渲染器_c++从零开始的3D图形学
小米14应用无法联网原因分析_小米14网络权限修复
正确连接J*aScript到HTML实现可点击图片与自定义事件处理


2025-11-25
浏览次数:次
返回列表