Les touches de signal telles que Ctrl+ Cenvoient un signal à tous les processus du groupe de processus de premier plan .
Dans le cas typique, un groupe de processus est un pipeline. Par exemple, dans head <somefile | sort
, le processus en cours d'exécution head
et le processus en cours d'exécution sort
sont dans le même groupe de processus, tout comme le shell, de sorte qu'ils reçoivent tous le signal. Lorsque vous exécutez un travail en arrière-plan ( somecommand &
), ce travail se trouve dans son propre groupe de processus, donc appuyer sur Ctrl+ Cne l'affecte pas.
Le timeout
programme se place dans son propre groupe de processus. Du code source:
/* Ensure we're in our own group so all subprocesses can be killed.
Note we don't just put the child in a separate group as
then we would need to worry about foreground and background groups
and propagating signals between them. */
setpgid (0, 0);
Lorsqu'un délai d'expiration se produit, timeout
passe par le simple moyen de tuer le groupe de processus dont il est membre. Puisqu'il s'est placé dans un groupe de processus séparé, son processus parent ne sera pas dans le groupe. L'utilisation d'un groupe de processus ici garantit que si l'application enfant se transforme en plusieurs processus, tous ses processus recevront le signal.
Lorsque vous exécutez timeout
directement sur la ligne de commande et appuyez sur Ctrl+ C, le SIGINT résultant est reçu à la fois par timeout
et par le processus enfant, mais pas par le shell interactif qui est timeout
le processus parent. Quand timeout
est appelé à partir d'un script, seul le shell exécutant le script reçoit le signal: timeout
ne l'obtient pas car il se trouve dans un groupe de processus différent.
Vous pouvez définir un gestionnaire de signal dans un script shell avec la fonction trap
intégrée. Malheureusement, ce n'est pas si simple. Considère ceci:
#!/bin/sh
trap 'echo Interrupted at $(date)' INT
date
timeout 5 sleep 10
date
Si vous appuyez sur Ctrl+ Caprès 2 secondes, cela attend toujours les 5 secondes complètes, puis imprimez le message «Interrompu». En effet, le shell s'abstient d'exécuter le code d'interruption lorsqu'un travail de premier plan est actif.
Pour y remédier, exécutez le travail en arrière-plan. Dans le gestionnaire de signaux, appelez kill
pour relayer le signal au timeout
groupe de processus.
#!/bin/sh
trap 'kill -INT -$pid' INT
timeout 5 sleep 10 &
pid=$!
wait $pid
bg
offg
. Quoi qu'il en soit, y a-t-il une différence entre vos 1er et 3e exemples?