Quelle est la meilleure façon d’implémenter l’action d’arrêt pour le signal d’interruption du serveur?

J’écris un petit serveur avec une boucle pour toujours et je veux pouvoir l’arrêter correctement, par exemple sur 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 callback_wrapper; void signal_handler(int) { callback_wrapper(); } } int main() { std::unique_ptr 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; } 

Et j’ai les questions suivantes:

  1. Quel est le type de run_flag_variable je devrais utiliser? L’utilisation de volatile sig_atomic_t correcte?
  2. Est-il sécuritaire d’appeler la méthode stop dans signal_handler ?

Semble presque légitime, sauf que je pourrais suggérer quelques améliorations. On n’est pas si sérieux: si vous ne pouvez utiliser que C ++, je veux dire les primitives de l’en-tête csignal , et éviter les volatile nous disposons déjà, plus vous pouvez lire ma réponse, la question n’est pas très pertinente. Pour le second, il y a beaucoup de réserves avec ce que vous pouvez et ne pouvez pas faire dans les gestionnaires de signaux, C ++ – 14,17 ont beaucoup changé, en plus il y a des manières non standard, mais spécifiques à la plate-forme. vous devez utiliser des éléments atomiques / volatiles, sinon vous devez avoir une bonne raison et être spécifique à la plate-forme.

 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(new Server); std::signal(SIGINT, &signal_handler); server->loop(); return 0; } 

J’ai donné un exemple de la façon dont vous pouvez suivre un ensemble de conditions globales à partir d’un gestionnaire de signaux, et un local, si vous en avez besoin, défini à partir d’autres threads, par exemple.