comment gérer le code qui n’exécute jamais

J’ai un code qui ressemble à ceci et je ne sais pas comment gérer la partie qui ne sera jamais exécutée car une partie de ce code s’exécute en boucle infinie en attendant des connexions et quand je termine le programme, il se termine seulement là.

main(){ // do some stuff.... while(1) { int newFD = accept(sockFD, (struct sockaddr *)&client_addr, &client_addr_size); if(newFD == -1) { std::cerr << "Error while Accepting on socket" << std::endl; continue; } if(!fork()) { close(sockFD); // close child's sockfd - not needed here // lalala do stuff send message here close(newFD); // finally close its newFD - message sent, no use return 0; } close(newFD); // close parent's newFD - no use here } // now execution never reaches here close(sockFD); // so how to handle this? freeaddrinfo(res); // and this? return 0; } 

Vous pouvez et devriez probablement append un gestionnaire de sortie si votre code doit être utilisé par d’autres personnes ou si vous voulez simplement le nettoyer. Dans votre gestionnaire d’exit, vous pouvez basculer un indicateur qui met fin à la boucle while() . Le code suivant fonctionnera correctement à 100% pour ce cas d’utilisation et est fiable et multiplateforme, mais si vous voulez faire des choses plus compliquées, vous devez utiliser des fonctions spécifiques à un système d’exploitation thread-safe ou quelque chose comme Boost ou C ++ 11.

Déclarez d’abord deux variables globales, rendez-les volatiles pour que le compilateur nous oblige toujours à lire ou à écrire sa valeur de mémoire réelle. Si vous ne le déclarez pas volatile, il est possible que le compilateur puisse mettre sa valeur dans un registre, ce qui ne fonctionnera pas. Avec volatile set, il lira l’emplacement de la mémoire sur chaque boucle et fonctionnera correctement, même avec plusieurs threads.

 volatile bool bRunning=true; volatile bool bFinished=false; 

et au lieu de votre boucle while(1) {} , changez-la en ceci

 while(bRunning) { dostuff } bFinished=true; 

Dans votre gestionnaire d’exit, définissez simplement bRunning=false;

 void ExitHandler() { bRunning=false; while(bFinished==false) { Sleep(1); } } 

Vous n’avez pas spécifié de système d’exploitation, mais il semble que vous soyez basé sur Linux, pour définir un gestionnaire sous Linux, vous en avez besoin.

 void ExitHandler(int s) { bRunning=false; } int main() { struct sigaction sigIntHandler; sigIntHandler.sa_handler = ExitHandler; sigemptyset(&sigIntHandler.sa_mask); sigIntHandler.sa_flags = 0; sigaction(SIGINT, &sigIntHandler, NULL); while(bRunning) { dostuff } ...error_handling... } 

Et sur Windows lorsque vous êtes une application de console, voici ce qui suit.

 BOOL WINAPI ConsoleHandler(DWORD CEvent) { switch (CEvent) { case CTRL_C_EVENT: case CTRL_BREAK_EVENT: case CTRL_CLOSE_EVENT: case CTRL_LOGOFF_EVENT: case CTRL_SHUTDOWN_EVENT: bRunning = false; while (bFinished == false) Sleep(1); break; } return TRUE; } int main() { SetConsoleCtrlHandler(ConsoleHandler, TRUE); while(bRunning() { dostuff } ...error_handling... } 

Notez la nécessité de tester et d’attendre bFinished ici. Si vous ne le faites pas sous Windows, votre application n’aura peut-être pas le temps de s’arrêter car le gestionnaire d’exit est appelé par un thread spécifique au système d’exploitation. Sous Linux, ce n’est pas nécessaire et vous devez quitter votre gestionnaire pour que votre thread principal continue.

Une autre chose à noter est que par défaut, Windows ne vous donne que 5 secondes pour vous arrêter avant de vous terminer. Cela est regrettable dans de nombreux cas et si vous avez besoin de plus de temps, vous devrez modifier le paramètre du registre (mauvaise idée) ou implémenter un service mieux adapté. Pour votre cas simple, ça ira.

Pour ce faire, le système d’exploitation veillera à libérer correctement les ressources lors de l’arrêt. Cependant, plus généralement, vous devez toujours vous assurer que les ressources allouées ne s’emstacknt pas pendant l’exécution du programme, même si elles sont récupérées automatiquement par le système d’exploitation, car une telle fuite de ressources influencera encore le comportement et les performances de votre programme.

Maintenant, en ce qui concerne les ressources disponibles, il n’y a aucune raison de ne pas les traiter comme toutes les ressources en C ++. La règle acceptée est de les lier à un object qui les libèrera dans leur destructeur, voir aussi l’idiome RAII. De cette façon, même si, à un stade ultérieur, quelqu’un a ajouté une déclaration de break , le code se comporterait toujours correctement.

BTW: Le problème le plus grave que je vois ici est le manque de traitement des erreurs en général.