在中断信号上对服务器实施停止动作的最佳方法是什么?

时间:2018-08-11 13:33:13

标签: c++ c++11 server

我正在编写一个具有永久循环的小型服务器,并且希望能够正确停止它,例如在Ctrl + C(SIGINT)上。

class Server
{
...
public:
  void loop()
  {
    while(_run_flag)
    {
      // do something
    }
  }
  void stop()
  {
    _run_flag = 0;
  }
...
private:
  volatile sig_atomic_t _run_flag = 1;
};

namespace
{
std::function<void()> callback_wrapper;

void signal_handler(int)
{
  callback_wrapper();
}

}

int main()
{
  std::unique_ptr<WSGIServer> server = CreateServer("127.0.0.1", 4009);
  callback_wrapper = [&](){ server->stop(); };

  struct sigaction sigIntHandler;
  sigIntHandler.sa_handler = signal_handler;
  sigemptyset(&sigIntHandler.sa_mask);
  sigIntHandler.sa_flags = 0;
  sigaction(SIGINT, &sigIntHandler, NULL);

  server->loop();

  return 0;
}

我有以下问题:

  1. 我应该使用run_flag_variable的哪种类型?使用volatile sig_atomic_t可以吗?
  2. stop中调用signal_handler方法安全吗?

1 个答案:

答案 0 :(得分:1)

似乎几乎是合法的,除了我不能提出什么改进。一个不是那么严重:如果您只能使用C ++,我的意思是基元形成csignal头,并尝试避免volatile我们已经拥有atomic的东西,更多的您可以阅读我的答案{ {3}},认为这个问题没有太大的意义。第二,在信号处理程序中您可以做和不能做的事情有很多警告,C ++-14,17除了有一些非标准的,但特定于平台的做事方式之外,已经发生了很多变化,但是最简单的规则是您必须使用原子/易失性材料,否则,必须有充分的理由并且针对特定平台。

std::atomic_bool global_run_flag(true);

class Server {
public:
  Server() : _local_run_flag(true) {}

  void loop() {
    while (_local_run_flag && global_run_flag) {
      // do something
    }
  }
  void stop() { _local_run_flag = false; }

private:
  std::atomic_bool _local_run_flag;
};

void signal_handler(int) { global_run_flag = false; }

int main() {
  std::unique_ptr<Server> server(new Server);

  std::signal(SIGINT, &signal_handler);

  server->loop();

  return 0;
}

我举了一个示例,您如何跟踪信号处理程序中的全局条件集,例如,如果需要,可以跟踪其他线程中的局部条件。