循环期间具有更改订阅的发布服务器/订阅服务器
Publisher/Subscriber with changing subscriptions during loop
这更像是我的一个通用设计查询。我通过维护订阅者列表实现了发布/订阅模式。当要发布的事件发生时,我循环遍历订阅者,并依次将事件推送给每个订阅者。
当由于该出版物、软件深处的某个地方、另一个组件或事件,所描述的组件决定自行取消订阅时,就会出现我的问题。这样做会使我的迭代器失效并导致崩溃。
解决这个问题的最佳方法是什么?我一直在考虑将整个发布循环包装成一个try-catch块,但这意味着一些订阅者错过了有人取消订阅的特定订阅,这似乎有点过头了。然后我尝试将其反馈,例如,我将void发布调用转换为bool发布调用,当订阅者想要删除时,该调用返回true,这在这种情况下有效,但如果另一个订阅者取消订阅,则无效。然后我想把取消订阅请求"缓存"在某个地方,并在循环完成后释放它们,但这似乎有点过头了。然后我考虑将迭代器存储为一个类成员,这样我就可以从外部操作迭代器,但这会变得很混乱(比如取消订阅订阅者1,迭代器指向2,容器是一个向量,然后迭代器必须递减)。我想我可能更喜欢后两种解决方案中的一种,但两者似乎都不理想。
这是常见问题吗?有没有更优雅的解决方案?
您可以在发布期间禁止订阅操作,也可以使用适当的数据结构来保存订阅列表,或者两者兼而有之。
假设您将订阅者保持在std::list
中,则可以运行循环:
for(iterator_type it = subs.begin(); it != subs.end(); ) {
iterator_type next = it;
++next;
it->notifier();
it = next;
}
这样,如果删除了当前项,那么next
中仍然有一个有效的迭代器。当然,您仍然不允许在发布期间任意删除(如果删除了next
呢?)。
要允许任意删除,请将项目标记为无效,并推迟删除其列表,直到安全为止:
... publication loop ...
dontRemoveItems = true;
for(iterator_type it = subs.begin(); it != subs.end(); ++it) {
if(it->valid)
it->notifier();
}
std::erase(std::remove_if(...,, IsNotValid),...);
dontRemoveItems = false;
其他地方,
... removal code:
if(dontRemoveItems) item->valid = false;
else subs.erase(item);
相关文章:
- 如何循环打印顶点结构
- 如何在C++中从两个单独的for循环中添加两个数组
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 正在尝试了解输入验证循环
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 循环后如何继续阅读
- Ardunio UNO解决了多个重叠的定时器循环
- Eigen如何在容器循环中干净地附加矩阵
- 在某些循环内使用vector.push_back时出现分段错误
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- 为什么我的for循环不能正确获取argv
- C++服务器程序循环打印
- 运行 boost::asio 异步服务器以及命令循环
- 将游戏服务器线程循环限制为 30FPS,而无需游戏引擎/渲染窗口
- 如何在不关闭服务器套接字的情况下在C++客户端的主循环中接收数据?
- 服务器程序处于无限循环中.如何检查它
- 我如何设置一个不断侦听循环与接收udp套接字,而不使它成为一个服务器
- 如何为服务器编写主循环
- 当主线程在无限循环中运行时,用QTcpSocket::write写入的字节没有被服务器接收
- 循环期间具有更改订阅的发布服务器/订阅服务器