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:
run_flag_variable
je devrais utiliser? L’utilisation de volatile sig_atomic_t
correcte? 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.