La première chose que vous devez accepter est que le threading est difficile.
Un "programme utilisant le threading" est aussi générique qu'un "programme utilisant la mémoire", et votre question est similaire à "comment ne pas corrompre la mémoire dans un programme utilisant la mémoire ?"
La façon de gérer un problème de threading est de limiter la façon dont vous utilisez les threads et le comportement des threads.
Si votre système de threading est un ensemble de petites opérations composées en un réseau de flux de données, avec la garantie implicite que si une opération est trop importante, elle est décomposée en opérations plus petites et/ou effectue des checkpoints avec le système, alors l'arrêt est très différent que si vous avez un thread qui charge une DLL externe qui l'exécute pendant une durée allant de 1 seconde à 10 heures à une durée infinie.
Comme pour la plupart des choses en C++, résoudre votre problème va tourner autour de la propriété, de la maîtrise et (en dernier recours) des astuces.
Comme pour les données en C++, chaque thread devrait être propriété de quelqu'un. Le propriétaire d'un thread devrait avoir un contrôle significatif sur ce thread, et être capable de dire que l'application est en train de s'arrêter. Le mécanisme d'arrêt devrait être robuste et testé, et idéalement connecté à d'autres mécanismes (comme l'arrêt précoce des tâches spéculatives).
Le fait que vous appelez exit(0) est un mauvais signe. Cela implique que votre thread d'exécution principale n'a pas de chemin d'arrêt propre. Commencez par là ; le gestionnaire d'interruption devrait signaler au thread principal que l'arrêt doit commencer, puis votre thread principal devrait s'arrêter en douceur. Tous les cadres de pile devraient se dérouler, les données devraient être nettoyées, etc.
Ensuite, le même type de logique qui permet cet arrêt propre et rapide devrait également être appliqué à votre code threadé.
Quiconque vous dit que c'est aussi simple qu'une variable de condition/un booléen atomique et un polling essaie de vous vendre quelque chose d'inepte. Cela ne fonctionnera que dans des cas simples si vous avez de la chance, et déterminer si cela fonctionne de manière fiable va être assez difficile.
0 votes
Vous "rejoignez" les fils créés. Si vous ne le faites pas et que vous quittez simplement un fil, alors il peut rester des fils flottants.
15 votes
Note : en général, il est inapproprié d'appeler
exit()
à partir d'un gestionnaire de signaux.1 votes
Je pense que vous pouvez appeler
_exit()
ou_Exit()
cependant.1 votes
@mathreadler: Je ne suis pas sûr que ce soit une exigence de C++ ISO, mais à ma connaissance, sur un système POSIX moderne,
exit()
ou_exit()
est nécessaire pour mettre fin à l'ensemble du processus, pas seulement au thread actuel. C'est pourquoi glibc2.3 (il y a de nombreuses années) a modifié_exit(2)
pour utiliser l'appel systèmesys_exit_group
de Linux au lieu desys_exit
, mettant fin à tous les threads (sans appeler de destructeurs ni quoi que ce soit).exit(3)
sur Linux utilise égalementsys_exit_group
.0 votes
@PeterCordes il est fort probable que tu as raison. Je n'ai pas codé beaucoup de programmes multi-threaded. Juste bidouillé un peu quand j'étais plus jeune.