Как я могу убить процесс <defunct>, чьим родителем является init?

27

Передача периодически висит на моем NAS. Если я отправляю SIGTERM, он не исчезает из списка процессов, а <defunct>рядом с ним появляется метка. Если я отправляю SIGKILL, он все равно не исчезает, и я не могу прекратить родительский, потому что родительский init. Единственный способ избавиться от процесса и перезапустить Transmission - это перезагрузить компьютер.

Я понимаю, что лучшее, что я могу сделать, это попытаться исправить Transmission (и я пробовал), но я новичок в компиляции, и я хотел убедиться, что мои торренты закончены, прежде чем я начну возиться с ним.

Энди Э
источник
3
Никто не заявляет об очевидном ... процесс <defunct>, принадлежащий init, должен быть невозможным! Это очень странная ситуация! Вы уверены?
JoelFan
@JoelFan: я просто искал это, чтобы убедиться, что я не забыл что-то важное. Зомби, которые являются детьми, initдолжны уходить довольно быстро, так initкак периодически ждут детей, так как одна из многих его общих задач ... это <defunct>то же самое, что и зомби?
Д.Шоули
1
неважно ... <defunct>это точно так же, как зомби. initбудет ждать своих детей, так что это никогда не должно происходить в теории. Интересно , что произойдет , если вы отправить SIGCHLDв init?
Д.Шоули
@JoelFan: да, я уверен. Значение для PPID было 1 (init), поэтому невозможно было SIGKILL процесса.
Энди Э
3
похож на unix.stackexchange.com/a/5648
tshepang

Ответы:

35

Вы не можете убить <defunct>процесс (также известный как процесс зомби), так как он уже мертв. Система сохраняет процессы зомби для родительского, чтобы собрать статус выхода. Если родитель не получает статус выхода, то процессы зомби останутся навсегда. Единственный способ избавиться от этих зомби-процессов - это убить родителя. Если родителем является init, вы можете только перезагрузиться.

Процессы зомби практически не потребляют ресурсов, поэтому нет необходимости снижать производительность. Хотя наличие зомби-процессов обычно означает, что в некоторых ваших программах есть ошибка. Инициировать обычно должны все дети. Если в init есть дети-зомби, значит, в init есть ошибка (или еще какая-то, но она есть).

http://en.wikipedia.org/wiki/Zombie_process

lesmana
источник
9
initникогда не может иметь детей зомби. Из статьи в Википедии: Когда процесс теряет своего родителя, init становится его новым родителем. Init периодически выполняет системный вызов wait, чтобы пожинать зомби с init в качестве родителя. Одна из initобязанностей - пожинать сирот и зомби без родителей.
Д.Шоули
14
@ D.Shawley: initмогут быть ошибки, хотя. У замены init runitбыла ошибка, которая вызывает эту проблему.
camh
2
У init могут быть недееспособные дети, возможно, из-за ошибки, но это возможно. Потому что я смотрю на один прямо сейчас.
Studgeek
Есть эта программа, которую я запустил из терминала и перешел в несуществующее состояние. Как объяснил @lesmana, когда я закрыл терминал (родительский), программа вышла полностью.
мк ..
6

Любой, кто пытается исправить исходный код Transmission C, должен прочитать об уловке «двойная вилка», чтобы избежать зомби и обработчиков сигналов ... и как ее можно использовать как часть интеллектуальной функции появления переменных (см. Spawning в Unix ).

excerpt from: 
   "Spawning in Unix", http://lubutu.com/code/spawning-in-unix

Double fork
This trick lets you spawn processes whilst avoiding zombies, without 
installing any signal handler. The first process forks and waits for its 
child; the second process forks and immediately exits and is reaped;
the third process is adopted by init, and executes the desired program. 
All zombies accounted for, since init is always waiting.

if(fork() == 0) {
   if(fork() == 0) {
       execvp(file, argv);
       exit(EXIT_FAILURE);
   }
   exit(EXIT_SUCCESS);
}
wait(NULL);
назар
источник
1
Двойная вилка предотвращает процессы зомби, заставляя ядро ​​установить для своего родителя значение PID 1, которое должно очищать зомби. Похоже, что Transmission уже делает это, так как его родитель уже обрабатывает 1.
Jander
1
Здесь есть несколько проблем. # 1: Только родитель должен звонить exit(3); _exit(2)вместо этого дети должны звонить (в противном случае вы получаете несколько сбросов stdio среди других вопросов) # 2: Это execvp(3)может использовать, perror(3)если это не удается № 3: Вы должны просто использовать signal(SIGCHLD, SIG_IGN)вместо всего этого беспорядка.
Кевин