Comment gérez-vous le nettoyage lorsque le programme reçoit un signal d'arrêt?
Par exemple, il existe une application à laquelle je me connecte et qui souhaite qu'une application tierce (mon application) envoie une finish
commande lors de la déconnexion. Quelle est la meilleure façon d'envoyer cette finish
commande lorsque mon application a été détruite avec un kill -9
?
edit 1: kill -9 ne peut pas être capturé. Merci les gars de m'avoir corrigé.
edit 2: Je suppose que ce cas serait quand celui qui appelle juste kill qui est le même que ctrl-c
kill -9
signifie pour moi: "Pars, processus immonde, loin avec toi!", sur lequel le processus cessera d'être. Immédiatement.kill
n'est pas la même chose que Ctrl-C, carkill
sans spécifier quel signal envoyer enverra SIGTERM, alors que Ctrl-C envoie SIGINT.Réponses:
Il est impossible pour aucun programme, dans n'importe quelle langue, de gérer un SIGKILL. C'est ainsi qu'il est toujours possible de terminer un programme, même si le programme est bogué ou malveillant. Mais SIGKILL n'est pas le seul moyen de terminer un programme. L'autre consiste à utiliser un SIGTERM. Les programmes peuvent gérer ce signal. Le programme doit gérer le signal en effectuant un arrêt contrôlé, mais rapide. Lorsqu'un ordinateur s'arrête, la dernière étape du processus d'arrêt envoie à chaque processus restant un SIGTERM, donne à ces processus quelques secondes de grâce, puis leur envoie un SIGKILL.
La façon de gérer cela pour autre chose que
kill -9
serait d'enregistrer un hook d' arrêt . Si vous pouvez utiliser ( SIGTERM ),kill -15
le hook d'arrêt fonctionnera. ( SIGINT )kill -2
FAIT que le programme quitte et exécute correctement les hooks d'arrêt.J'ai essayé le programme de test suivant sur OSX 10.6.3 et
kill -9
je n'ai PAS exécuté le crochet d'arrêt, comme prévu. Sur unkill -15
il N'exécuter le crochet d'arrêt à chaque fois.Il n'y a aucun moyen de gérer vraiment avec élégance un
kill -9
dans aucun programme.La seule vraie option pour gérer un
kill -9
est d'avoir un autre programme de surveillance pour que votre programme principal disparaisse ou d'utiliser un script wrapper. Vous pouvez le faire avec un script shell qui interroge laps
commande à la recherche de votre programme dans la liste et agit en conséquence lorsqu'il disparaît.la source
Il existe des moyens de gérer vos propres signaux dans certaines JVM - voir cet article sur HotSpot JVM par exemple.
En utilisant l'
sun.misc.Signal.handle(Signal, SignalHandler)
appel de méthode interne de Sun, vous pouvez également enregistrer un gestionnaire de signaux, mais probablement pas pour des signaux commeINT
ouTERM
tels qu'ils sont utilisés par la JVM.Pour être en mesure de gérer n'importe quel signal, vous devez sauter hors de la JVM et dans le territoire du système d'exploitation.
Ce que je fais généralement pour (par exemple) détecter une terminaison anormale est de lancer ma JVM dans un script Perl, mais que le script attende la JVM en utilisant l'
waitpid
appel système.Je suis alors informé de chaque sortie de la machine virtuelle Java, de la raison de sa sortie, et je peux prendre les mesures nécessaires.
la source
INT
etTERM
avecsun.misc.Signal
, mais vous ne pouvez pas gérerQUIT
car la JVM le réserve pour le débogage, niKILL
parce que le système d'exploitation mettra fin immédiatement à la JVM. Tenter de gérer l'un ou l'autre lèvera unIllegalArgumentException
.Je m'attendrais à ce que la JVM interrompt gracieusement (
thread.interrupt()
) tous les threads en cours d'exécution créés par l'application, au moins pour les signauxSIGINT (kill -2)
etSIGTERM (kill -15)
.De cette façon, le signal leur sera transmis, permettant une annulation de thread et une finalisation des ressources en douceur de la manière standard .
Mais ce n'est pas le cas (au moins dans ma mise en œuvre JVM:
Java(TM) SE Runtime Environment (build 1.8.0_25-b17), Java HotSpot(TM) 64-Bit Server VM (build 25.25-b02, mixed mode)
.Comme l'ont commenté d'autres utilisateurs, l'utilisation de hooks d'arrêt semble obligatoire.
Alors, comment puis-je gérer cela?
Eh bien d'abord, je m'en fiche dans tous les programmes, seulement dans ceux où je veux garder une trace des annulations d'utilisateurs et des fins inattendues. Par exemple, imaginez que votre programme java est un processus géré par d'autres. Vous voudrez peut-être différencier s'il a été terminé correctement (à
SIGTERM
partir du processus gestionnaire) ou si un arrêt s'est produit (afin de relancer automatiquement le travail au démarrage).Comme base, je rends toujours mes threads de longue durée régulièrement au courant de l'état interrompu et jette un message
InterruptedException
s'ils sont interrompus. Cela permet la finalisation de l'exécution de manière contrôlée par le développeur (produisant également le même résultat que les opérations de blocage standard). Ensuite, au niveau supérieur de la pile de threads,InterruptedException
est capturé et un nettoyage approprié est effectué. Ces threads sont codés pour savoir comment répondre à une demande d'interruption. Conception à haute cohésion .Donc, dans ces cas, j'ajoute un hook d'arrêt, qui fait ce que je pense que la JVM devrait faire par défaut: interrompre tous les threads non démon créés par mon application qui sont toujours en cours d'exécution:
Application de test complète sur github: https://github.com/idelvall/kill-test
la source
Vous pouvez l'utiliser
Runtime.getRuntime().addShutdownHook(...)
, mais vous ne pouvez pas être assuré qu'il sera appelé dans tous les cas .la source
Il y a une façon de réagir à un kill -9: c'est d'avoir un processus séparé qui surveille le processus en cours de destruction et nettoie après cela si nécessaire. Cela impliquerait probablement IPC et serait un peu de travail, et vous pouvez toujours le remplacer en supprimant les deux processus en même temps. Je suppose que cela ne vaudra pas la peine dans la plupart des cas.
Quiconque tue un processus avec -9 devrait théoriquement savoir ce qu'il fait et que cela peut laisser les choses dans un état incohérent.
la source