c++ - 如何在 boost HTML3 示例中向服务器发送 SIGTERM 或 SIGINT 信号?

标签 c++ multithreading boost signals boost-asio

我使用 boost 中的 HTML Server 3 示例作为我的学习工具 ( http://www.boost.org/doc/libs/1_53_0/doc/html/boost_asio/examples.html#boost_asio.examples.http_server_3 ) 进行异步消息处理。

我已经采取了这个例子,并将其变成了一个带有服务器对象的库,我可以在我的程序中实例化。我对上面的示例所做的唯一一件事就是删除 main.cpp 并将其编译为库。它的工作范围是我可以在代码中实例化服务器对象,并从命令行向它传递消息。

我正在努力的是如何优雅地终止服务器。从示例代码中我看到了这一点:

server::server(const std::string& address, const std::string& port,  
               std::size_t thread_pool_size,
               Handler &handler)  
        : thread_pool_size_(thread_pool_size),  
          signals_(io_service_),  
          acceptor_(io_service_),  
          new_connection_(),  
          request_handler_(handler)  
{  
  // Register to handle the signals that indicate when the server should exit.  
  // It is safe to register for the same signal multiple times in a program,  
  // provided all registration for the specified signal is made through Asio.  
  signals_.add(SIGINT);  
  signals_.add(SIGTERM);  
  signals_.async_wait(boost::bind(&server::handle_stop, this));

因此设置了一个异步线程来监听信号并响应它们

我已在程序的线程中实现了此服务器对象,如下所示:

class ServerWorker
{
public:
    ServerWorker(std::string theHost, std::string thePort)
    {
        Host = theHost;
        Port = thePort;
    }
    void Start()
    {
        try
        {
            MYRequestHandler handler;
            int nCores = boost::thread::hardware_concurrency();
            server *mServer = new server(Host, Port, nCores, handler);
            svr->run();
        }
        catch(std::exception &e) { /* do something */ }
    }
    void Stop()
    {
        mServer->stop(); // this should raise a signal and send it to the server
                         // but don't know how to do it
    }
private:
    std::string Host;
    std::string Port;
    server *mServer;
};

TEST(BSGT_LBSSERVER_STRESS, BSGT_SINGLETON)
{
    // Launch as server on a new thread
    ServerWorker sw(BSGT_DEFAULT_IPADDRESS, BSGT_DEFAULT_PORT_STR);
    boost::function<void()> th_func = boost::bind(&ServerWorker::Start, &sw);
    boost::thread swThread = boost::thread(th_func);

    // DO SOMETHING

    // How do I signal the server in the swThread to stop?    
}

如何在服务器对象上实现 stop() 方法以向其自身发送信号?我尝试过:
1) raise(SIGTERM) - 终止整个程序
2) raise(SIGINT) - 终止整个程序

最佳答案

raise() 适合拥有进程信号本身。

void ServerWorker::Stop()
{
  std::raise(SIGTERM);
}

请注意,raise() 是异步的。它会发出信号并立即返回。因此,在 io_service 处理排队的 SignalHandler 之前,控制可能会继续。

void run_server()
{
  // Launch as server on a new thread
  ServerWorker server_worker(...);
  boost::thread worker_thread([&server_worker]() { server_worker.Start(); });

  ...

  // Raises SIGTERM.  May return before io_service is stopped.
  server_worker.Stop();

  // Need to synchronize with worker_thread.  The `worker_thread` may still be
  // in `ServerWorker::Start()` which would go out of scope.  Additionally,
  // the `worker_thread` is joinable, so its destructor may invoke 
  // `std::terminate()`.
}

这是一个最小的示例 demonstrating使用 Boost.Asio 信号处理、raise() 和同步:

#include <cassert>
#include <csignal>
#include <iostream>
#include <thread>
#include <boost/asio.hpp>

int main()
{
  boost::asio::io_service io_service;

  // Prevent io_service from running out of work.
  boost::asio::io_service::work work(io_service);

  // Boost.Asio will register an internal handler for SIGTERM.
  boost::asio::signal_set signal_set(io_service, SIGTERM);
  signal_set.async_wait(
    [&io_service](
       const boost::system::error_code& error,
       int signal_number)
    {
      std::cout << "Got signal " << signal_number << "; "
                   "stopping io_service." << std::endl;
      io_service.stop();
    });

  // Raise SIGTERM.
  std::raise(SIGTERM);

  // By the time raise() returns, Boost.Asio has handled SIGTERM with its
  // own internal handler, queuing it internally.  At this point, Boost.Asio
  // is ready to dispatch this notification to a user signal handler
  // (i.e. those provided to signal_set.async_wait()) within the
  // io_service event loop.
  std::cout << "io_service stopped? " << io_service.stopped() << std::endl;
  assert(false == io_service.stopped());

  // Initiate thread that will run the io_service.  This will invoke
  // the queued handler that is ready for completion.
  std::thread work_thread([&io_service]() { io_service.run(); });

  // Synchornize on the work_thread.  Letting it run to completion.
  work_thread.join();

  // The io_service has been explicitly stopped in the async_wait
  // handler.
  std::cout << "io_service stopped? " << io_service.stopped() << std::endl;
  assert(true == io_service.stopped());
}

输出:

io_service stopped? 0
Got signal 15; stopping io_service.
io_service stopped? 1

关于c++ - 如何在 boost HTML3 示例中向服务器发送 SIGTERM 或 SIGINT 信号?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32792888/

相关文章:

c++ - Open() 系统调用文件描述器

c++ - 为什么串口发送数据时会跳数据?

c++ - 通过自定义语法使用 Boost Spirit 的流解析器

c++ - Qt - 改变 QGraphicsRectItem 的旋转中心

c++ - "Control reaches end on non-void function"with do { 返回结果; } 而(条件);

java - 单例类中的方法是线程安全的吗?

c++ - 创建线程总是对性能有好处吗?

c++ - 在 C++11 中安全明确地操作原子变量

c++ - 我如何遍历目录并识别或省略 NTFS 连接(symlink-ish)

spirit boost : force an attribute on a no-attribute parser