首页 > 解决方案 > 在中断信号上实现服务器停止操作的最佳方法是什么?

问题描述

我正在编写一个带有永久循环的小型服务器,我希望能够正确停止它,例如,在 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

标签: c++c++11server

解决方案


似乎几乎是合法的,除了我可以建议一些改进。一个不是那么严重:如果你只能使用 C++,我的意思是原语形式csignal的标题,并尽量避免volatile我们已经有东西,更多你可以在这里atomic阅读我的答案,认为这个问题无关紧要。第二,在信号处理程序中你可以做什么和不能做什么有很多警告,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;
}

我举了一个例子,你可以如何跟踪一个信号处理程序的全局条件集,以及一个本地的,如果你需要的话,从其他线程设置,例如。


推荐阅读