使用Boost.Asio执行干净关闭的标准方法

Tim*_*003 14 c++ signals console-application boost-asio

我正在使用Boost.Asio在C++中编写跨平台服务器程序.遵循此页面上的HTTP Server示例,我想在不使用特定于实现的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
}
Run Code Online (Sandbox Code Playgroud)

Cha*_*esB 18

Boost.Asio的1.5.3版本(将在即将发布的1.47版本中集成?)具有以下signal_set类别:

#include <boost/asio/signal_set.hpp>

// Register signal handlers so that the daemon may be shut down. You may
// also want to register for other signals, such as SIGHUP to trigger a
// re-read of a configuration file.
boost::asio::signal_set signals(io_service, SIGINT, SIGTERM);
signals.async_wait(
    boost::bind(&boost::asio::io_service::stop, &io_service));
Run Code Online (Sandbox Code Playgroud)

编辑

现在包含在Boost版本1.47中

  • 通过仅停止io_service并取消工作,一旦调用io_service的析构函数,您的应用程序就会遭受随机段错误。 (2认同)

Sam*_*ler 5

POSIX例如 HTTP服务器是一个很好的方式正常关闭.一个线程调用io_service::run而另一个线程等待信号sigwait.

或者,你可以安装一个信号处理程序,但它有点棘手.您可以在信号处理程序中调用一个非常小的异步信号安全函数列表.

例程处理程序必须非常小心,因为其他地方的处理在某个任意点被中断.POSIX具有"安全功能"的概念.如果信号中断了不安全的函数,并且处理程序调用了不安全的函数,则行为是未定义的.安全功能在各种标准中明确列出.

POSIX.1-2003列表是

_Exit()_ exit()abort()accept()access()aio_error()aio_return()aio_suspend()alarm()bind()cfgetispeed()cfgetospeed()cfsetispeed()cfsetospeed()chdir()chmod()chown( )clock_gettime()close()connect()creat()dup()dup2()execle()execve()fchmod()fchown()fcntl()fdatasync()fork()fpathconf()fstat()fsync()ftruncate ()getegid()geteuid()getgid()getgroups()getpeername()getpgrp()getpid()getppid()getsockname()getsockopt()getuid()kill()link()listen()lseek()lstat() mkdir()mkfifo()open()pathconf()pause()pipe()poll()posix_trace_event()pselect()raise()read()readlink()recv()recvfrom()recvmsg()rename()rmdir( )select()sem_post()send()sendmsg()sendto()setgid()setpgid()setsid()setsockopt()setuid()shutdown()sigaction()sigaddset()sigdelset()sigemptyset()sigfillset()sigismember ()signal()sigpause()sigpending()sigprocmask()sigqueue()sigset()sigsuspend()sleep()socket()socketpair()stat()symlink()sysconf()tcdrain()tcflow()tcflush()tcgetattr()tcgetpgrp()tcsendbreak()tcsetattr()tcsetpgrp()time()timer_getoverrun()timer_gettime()timer_settime()times()umask()uname()unlink()utime()wait()waitpid()write( ).

  • 我在[本页]找到了一个函数列表.(http://linux.die.net/man/2/signal)但是,它是POSIX特有的.C标准是否对这些东西说了什么不同? (2认同)