关于正确关闭 Boost Beast 服务器的说明

问题描述 投票:0回答:1

我正在使用 Boost Beast 高级服务器示例(可在 Boost.org 获取),并将其用作我自己的服务器的基础。我的理解是,在这个例子中,会话和监听器都是自维持的对象;他们通过始终将自己的shared_ptr附加到回调处理程序来保持自己的活力。这种设计看起来非常优雅和实用,因为它似乎通过允许结构在没有挂起的异步操作时自毁来简化错误处理。

但是,我不清楚整个系统是如何关闭的。该代码首先调用 ioc.stop(),然后加入相应的线程。我最初认为 ioc.stop() 会处理任何挂起的处理程序和关联的共享指针的清理,但情况似乎并非如此。似乎更有可能的是,任何剩余的处理程序都被 ioc 本身的最终销毁所销毁,从而清理了任何剩余的共享指针。

在我的服务器实现中,我通过对 io_context 使用 unique_ptr 并在服务器的析构函数中显式重置它来处理它:

HTTPServer::HTTPServerImpl::~HTTPServerImpl()
{
    m_ioc->stop();

    for (auto& thread : m_iocThreads)
        thread.join();

    m_ioc.reset(); // reset the unique_ptr
}

我对这个关闭过程有几个问题:

1.) 就正确关闭所有套接字而言,~HTTPServerImpl 中的关闭过程(如示例中采用的那样)是否被认为是“干净的”?这到底是怎么发生的?当shared_ptrs析构时通过beast::tcp_stream和tcp::acceptor的析构函数?或者我应该通过一些weak_ptr在stop()之前显式调用cancel()/close()(主线程是否允许取消/关闭?它是线程安全的吗?)?是否所有异步操作在 m_ioc.reset() 期间中止,或者某些处理程序仍在执行(例如计时器)?

2.) stop() 在这种情况下到底做了什么?它只是阻止添加新的处理程序,还是还有更多的事情要做?文档中说“放弃未完成的操作”,这到底是什么意思?我不认为这会阻止任何事情。计时器也不会过早中止。

c++ boost-asio shared-ptr destructor boost-beast
1个回答
0
投票

似乎更有可能的是,任何剩余的处理程序都被 ioc 本身的最终销毁所销毁,从而清理了任何剩余的共享指针。

确实如此。

stop
只是“让世界停止”,但并没有“摆脱历史”。

析构函数可以。

Q1。就正确关闭所有套接字而言,~HTTPServerImpl 中的关闭过程(如示例中采用的那样)是否被认为是“干净的”?

是的。它隐式关闭所有套接字,因为它们仅通过任何挂起的异步操作中的引用计数保持活动状态 (

shared_from_this
)。

Q2。 stop() 在这种情况下到底做了什么?它只是阻止添加新的处理程序,还是还有更多的事情?

它停止调度程序。坦率地说,这是一个实施细节。它在功能上阻止任何处理程序运行并中断任何正在运行的事件循环(例如

io_context.run()
)。

一路上你问了很多问题,但我认为这一切都归结为这些:

或者我应该在 stop() 之前显式调用 cancel()/close()

我愿意,是的。请记住,您会考虑某种超时,以避免关闭本身陷入死锁的情况。这将是“防御拜占庭失败”(https://en.wikipedia.org/wiki/Byzantine_fault

通过一些weak_ptr

我通常就是这样做的。事实上,您可能可以使用

weak_ptr
cancel
session
作为关键字搜索我的答案来查找示例。

主线程允许取消/关闭吗?

只要其他线程可以访问 IO 对象就不需要。

线程安全吗?

取消没有特殊的安全保证,因此通常适用(例如https://www.boost.org/doc/libs/1_85_0/doc/html/boost_asio/reference/ip__tcp/socket.html#boost_asio.reference.ip__tcp .socket.thread_safety

现代化

我可能会这样写:

// 稍后发布 - 在我的新机器上进行压力测试需要一些时间

© www.soinside.com 2019 - 2024. All rights reserved.