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

时间:2011-01-09 15:12:35

标签: c++ signals console-application boost-asio

我正在使用Boost.Asio在C ++中编写跨平台服务器程序。遵循this page,上的HTTP Server示例,我想在不使用特定于实现的API的情况下处理用户终止请求。我最初尝试使用标准C信号库,但一直无法找到适合Asio的设计模式。 Windows example's设计似乎与最接近的信号库类似,但是存在竞争条件,其中可以在服务器对象被销毁之后调用控制台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
}

2 个答案:

答案 0 :(得分: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));

修改

现在included在Boost版本1.47

答案 1 :(得分:5)

posix example HTTP服务器是干净关闭的好方法。一个线程调用io_service::run,而另一个线程等待sigwait的信号。

或者,你可以安装一个信号处理程序,但它有点棘手。您可以在信号处理程序中调用very small list异步信号安全函数。

  

例程处理程序必须非常好   小心,因为在别处处理   被任意中断   点。 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()写()。