LINUX.ORG.RU

процесс-зомби


0

0

после выполнения стандартной структуры fork()-exec() дочерний процесс завершается, родитель остаётся работать дальше, но в таблице процессов остаётся зомби - дочерний процесс, до тех пор пока либо не завершится родитель, либо этих зомби (процедура повторяется множество раз) не станет настолько много, что ядро частично их удаляет (но не все). Как избежать появления процессов-зомби? Ответ можно прислать на biggod@folksnet.com

anonymous

man waitpid

Вызов waitpid можеш встроить в обработчик сигнала SIGCHLD

tvn
()
Ответ на: комментарий от idle

2idle (*) (2002-10-08 15:35:28.685):
> Или установить SIGCHLD в SIG_IGN - зомби не будет.
man signal:

"According to POSIX (B.3.3.1.3) you must not set the action
for SIGCHLD to SIG_IGN."

Die-Hard ★★★★★
()

2anonymous (*) (2002-10-08 07:50:02.923):
Да, кстати, стандартный способ избежания зомби на Юнихе -- двойной форк.
Первый порождает сына, второй - внука. Сын сразу выходит, а папа
делает wait (сразу отпускает, поскольку сын сделал exit), а внук работает.

Если хочешь полной "демонизации", перед вторым форком сделай нечто типа:

{
int i;
close(0);/*close stdin*/
open("/dev/null",O_RDONLY); /* reopen stdin */
close(1);/*close stdout*/
close(2);/*close stderr*/
if( (i=open("/dev/null",O_WRONLY))>0 )/*reopen stdout*/
dup(i); /* reopen stderr */
setsid(); /* Detach from the current process group and
obtain a new process group */
}

Die-Hard ★★★★★
()

Die-Hard wrote: > According to POSIX (B.3.3.1.3) you must not set the action > for SIGCHLD to SIG_IGN. Зато sus (single unix specification) это позволяет, и в linux это работает. Вообще, linux далеко не соответсвует posix, и не стремится. Хотя бы kill(-1, sig). Что касается double fork, я не назвал бы это стандартным способом борьбы с zombie, все таки лишние fork()+wait4(), два довольно тяжелых вызова... Скорее это действительно для "демонизации". Но работать будет, конечно.

idle ★★★★★
()

idle (*) (2002-10-09 15:21:20.19):
> ...и в linux это работает.
Честно говоря, не пробовал, убоявшись продолжения комментария в man signal:
"According to POSIX (B.3.3.1.3) you must not set the action
for SIGCHLD to SIG_IGN. Here the BSD and SYSV behaviours
differ, causing BSD software that sets the action for
SIGCHLD to SIG_IGN to fail on Linux."
А, вообще, в силу специфики работы, я маниакально озабочен переносимостью.


> ...лишние fork()+wait4(), два довольно тяжелых вызова...
Кстати, я там лажу спорол (очепятался):
Die-Hard (*) (2002-10-09 00:07:43.745):
> Если хочешь полной "демонизации", перед вторым форком сделай нечто типа:...
Надо не "перед вторым форком", а ПОСЛЕ. Тогда второй форк будет легким:
поскольку папа сразу вылетит без телодвижений, его страницы памяти не отожруться.

А wait() не лишний - папа (ставший дедушкой) все равно его делать должен
(если SIGCHLD не игнорировать)

> Скорее это действительно для "демонизации".
Ну да, естественно. Ежели плодить двойные форки в бесконечном цикле, мало не
покажется...


2anonymous (*) (2002-10-08 07:50:02.923):
Специально повторяю:
Кстати, я там лажу спорол (очепятался):
Die-Hard (*) (2002-10-09 00:07:43.745):
> Если хочешь полной "демонизации", перед вторым форком сделай нечто типа:
Надо не перед вторым форком, а ПОСЛЕ. Тогда второй форк будет легким:
поскольку папа сразу вылетит без телодвижений, его страницы памяти не отожруться.

Die-Hard ★★★★★
()

Чего-то я не понял... Что значит "легкий форк" ? И что означает "страницы памяти не отожрутcя" ? Хотя делать daemonize() нужно, конечно, после второго fork()'а.

idle ★★★★★
()
Ответ на: комментарий от idle

> ...что означает "страницы памяти не отожрутcя" ?
Ну, типа - то и значит :)

Нет обращения к адресному пространству - соответственно, copy-on-write
концепция, принятая в большинстве систем (и в Линухе тоже), приведет к тому,
что ни какого копирования не будет. Типа связки vfork()+exec() в старых BSD.

Die-Hard ★★★★★
()

Во-первых, обращение к адресному пространству есть.
Значение fork() == 0 проверяем? exit() делаем?

Во-вторых, COW действует постранично.

В любом случае fork() во время dup_mmap() проходит по всем
страницам процесса и ставит COW на те из них, которые writeble
и не shared. При этом копируются дескрипторы страниц, содержимое
их _не_ копируется. См. mm/memory.c:copy_page_range().

Эта операция и занимает большую часть времени во время fork()'а.
Так что замедлить fork() можно, если перед ним увеличить адресное
пространство процесса, напр. malloc()/mmap(). Так что daemonize
код на скорость последующего fork() не повлияет никак.

В накладные расходы на fork() входит также и то, что _после_ его
выполнения и parent, и child получают page_fault при записи в страницы,
которые уже находятся в памяти - в этот момент и происходит copy-on-write,
т.е. копируется _содержимое_ страницы.

В случае vfork() ничего этого не происходит. child работает в
адресном пространстве родителя (типа thread), а тот ждет в семафоре
сигнала о его завершении, после чего возвращается из vfork().
Поэтому vfork()+exec() быстрее (и опаснее).

idle ★★★★★
()
Ответ на: комментарий от idle

2idle (*) (2002-10-10 10:18:12.039):

> Во-первых, обращение к адресному пространству есть.
> Значение fork() == 0 проверяем? exit() делаем?
Ну, да, ты прав, без этого - никак. Но, все ж, минимизируем кол-во отжираемых страниц.

> В случае vfork() ничего этого не происходит. child работает в адресном пространстве
> родителя
Да, аналогия с vfork() была не верная.

Согласен, что fork() имеет некий оверхед - но он в большинстве случаев пренебрежим.
Если ты форкаешь процессы, которые работают хотя бы по несколько секунд, то на
накладные расходы, связанные с лишним вызовом fork(), можно смело положить.

Die-Hard ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.