我正在编写一个具有永久循环的小型服务器,并且希望能够正确停止它,例如在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;
}
我有以下问题:
run_flag_variable
的哪种类型?使用volatile sig_atomic_t
可以吗?stop
中调用signal_handler
方法安全吗?答案 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;
}
我举了一个示例,您如何跟踪信号处理程序中的全局条件集,例如,如果需要,可以跟踪其他线程中的局部条件。