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

时间:2015-09-26 02:02:14

标签: 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)加注(SIGTERM) - 杀死整个程序
2)加注(SIGINT) - 杀死整个程序

1 个答案:

答案 0 :(得分:4)

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()`.
}

以下是使用Boost.Asio信号处理,raise()和同步的最小示例demonstrating

#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