使用 Boost.Asio 执行干净关闭的标准方法
我正在使用 Boost.Asio 用 C++ 编写一个跨平台服务器程序。遵循此页面上的 HTTP 服务器示例, 我想在不使用特定于实现的 API 的情况下处理用户终止请求。我最初尝试使用标准 C 信号库,但一直无法找到适合 Asio 的设计模式。 Windows 示例的 设计似乎与最接近的信号库相似,但是存在一个竞争条件,即在服务器对象完成后可以调用控制台 ctrl 处理程序被摧毁了。我试图避免 C++ 标准指定的未定义行为。
是否有标准(且正确)的方法来停止服务器?
为了说明使用 C 信号库的问题:
#include <csignal>
#include <functional>
#include <boost/asio.hpp>
using std::signal;
using boost::asio::io_service;
namespace
{
std::function<void ()> sighandler;
}
extern "C"
{
static void handle_signal(int);
}
void handle_signal(int)
{
// error - undefined behavior
sighandler();
}
int main()
{
io_service s;
sighandler = std::bind(&io_service::stop, &s);
auto old_sigint = signal(SIGINT, &handle_signal);
if (old_sigint == SIG_IGN)
// race condition? raise SIGINT before I can set ignore back
signal(SIGINT, SIG_IGN);
auto old_sigterm = signal(SIGTERM, &handle_signal);
if (old_sigterm == SIG_IGN)
// race condition? raise SIGTERM before I can set ignore back
signal(SIGTERM, SIG_IGN);
s.run();
// reset signals so I can clear reference to io_service
if (old_sigterm != SIG_IGN)
signal(SIGTERM, SIG_DFL);
if (old_sigint != SIG_IGN)
signal(SIGINT, SIG_DFL);
// clear reference to io_service, but can I be sure that handle_signal
// isn't being executed?
sighandler = nullptr;
// io_service is destroyed
}
I'm writing a cross-platform server program in C++ using Boost.Asio. Following the HTTP Server example on this page, I'd like to handle a user termination request without using implementation-specific APIs. I've initially attempted to use the standard C signal library, but have been unable to find a design pattern suitable for Asio. The Windows example's design seems to resemble the signal library closest, but there's a race condition where the console ctrl handler could be called after the server object has been destroyed. I'm trying to avoid undefined behavior as specified by the C++ standard.
Is there a standard (and correct) way to stop the server?
To illustrate problems with using the C signal library:
#include <csignal>
#include <functional>
#include <boost/asio.hpp>
using std::signal;
using boost::asio::io_service;
namespace
{
std::function<void ()> sighandler;
}
extern "C"
{
static void handle_signal(int);
}
void handle_signal(int)
{
// error - undefined behavior
sighandler();
}
int main()
{
io_service s;
sighandler = std::bind(&io_service::stop, &s);
auto old_sigint = signal(SIGINT, &handle_signal);
if (old_sigint == SIG_IGN)
// race condition? raise SIGINT before I can set ignore back
signal(SIGINT, SIG_IGN);
auto old_sigterm = signal(SIGTERM, &handle_signal);
if (old_sigterm == SIG_IGN)
// race condition? raise SIGTERM before I can set ignore back
signal(SIGTERM, SIG_IGN);
s.run();
// reset signals so I can clear reference to io_service
if (old_sigterm != SIG_IGN)
signal(SIGTERM, SIG_DFL);
if (old_sigint != SIG_IGN)
signal(SIGINT, SIG_DFL);
// clear reference to io_service, but can I be sure that handle_signal
// isn't being executed?
sighandler = nullptr;
// io_service is destroyed
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
Boost.Asio 版本 1.5.3(将集成到即将发布的 boost 1.47 版本中?)具有
signal_set
类:编辑
现在包含在 Boost 版本 1.47 中
Version 1.5.3 of Boost.Asio (to be integrated in upcoming boost 1.47 release?) has the
signal_set
class:EDIT
Now included in Boost version 1.47
posix 示例 HTTP 服务器是干净关闭的好方法。一个线程调用 io_service::run,而另一个线程则使用 sigwait 等待信号。
或者,您可以安装信号处理程序,但它稍微棘手一些。您可以从信号中调用非常小的异步信号安全函数列表处理程序。
The posix example HTTP server is a good way to cleanly shutdown. One thread invokes
io_service::run
while another waits for a signal withsigwait
.Alternatively, you can install a signal handler but that it slightly trickier. There's a very small list of async-signal-safe functions you can invoke from within a signal handler.