LINUX.ORG.RU

wait() and waitpid()


0

0

Объясните, пожалуйста, когда надо и когда не надо использовать функции wait() и waitpid() в программе? Соответственно, подразумеваю, что используется fork() для создания дочерних процессов.

Просто перед мной сейчас лежит книга "UNIX. Взаимодействие процессов", и там автор в редких (!!!) случаях использует данные функции? Чтение манов мою делему разрешить не помогли? Заранее спасибо.

anonymous

надо использовать во всех случаях когда дочерний процесс должен завершится РАНЬШЕ родителя.

если дочерний процесс должен работать после смерти родителя (например демон) то дёргать эти ф-и безсмысленно

cvv ★★★★★
()

Странный вопрос...

Ответ более-менее одназначный: надо всегда (если только речь не идет о "демонизации" через двойной форк).

> ...и там автор в редких (!!!) случаях использует данные функции?

Наверное, они подразумеваются. Просто в тот кусочек, что приводится, они не попали.

Die-Hard ★★★★★
()

эти функции предназанчены для очистки информации из таблицы процессов, т.е. для "уничтожения" зомби, зомби это не самип роцессы а информация об умерших процессах. wait ожидает завершеия любого процесса waitpid завершения конкрентого процесса или группы процессов. waitpid удобно использовать в обработчике сигнала SIGCHLD.

stalcker
()
Ответ на: комментарий от cvv

> надо использовать во всех случаях когда дочерний процесс должен завершится РАНЬШЕ родителя.

... кроме тех случаев, когда результат работы CHILD'а не представляет интереса для родителя, и он поэтому установил SIG_IGN для SIGCHLD.

anonymous
()
Ответ на: комментарий от stalcker

> waitpid удобно использовать в обработчике сигнала SIGCHLD.

Я не совсем понимаю, допустимо ли вызывать waitpid из обработчика сигнала, и совершенно не понимаю, зачем это нужно делать. Объясни, пожалуйста.

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

2anonymous (*) (13.02.2006 18:21:29):

Игнорирование SIGCHLD не совсем портабельно и уж совершенно нельзя в одной и той же программе игнорировать SIGCHLD и вызывать wait().

Die-Hard ★★★★★
()
Ответ на: комментарий от anonymous

anonymous (*) (13.02.2006 18:24:05):

> Я не совсем понимаю, допустимо ли вызывать waitpid из обработчика сигнала,

Допустимо

> и совершенно не понимаю, зачем это нужно делать.

Чтобы SIGCHLD не игнорировать.

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

>> и совершенно не понимаю, зачем это нужно делать.

>Чтобы SIGCHLD не игнорировать.

А как в обработчике SIGCHLD узнать, какой именно ребенок погиб, чтобы вызвать waitpid именно для него? И зачем это нужно делать (т.е. почему бы не использовать просто wait)?

anonymous
()
Ответ на: комментарий от Die-Hard

> Игнорирование SIGCHLD не совсем портабельно

Да, действительно, хотя для меня это новость.

man waitpid по этому поводу говорит: "The original POSIX standard left the behaviour of setting SIGCHLD to SIG_IGN unspecified. Later standards, including SUSv2 and POSIX 1003.1-2001 specify the behaviour just described as an XSI-compliance option."

Было бы интересно узнать, что такое "XSI-compliance option", однако получается, что есть какие-то еще options.

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

> А как в обработчике SIGCHLD узнать, какой именно ребенок погиб,
> чтобы вызвать waitpid именно для него? И зачем это нужно делать
> (т.е. почему бы не использовать просто wait)?

Может книжечку какую по программированию прочитаешь или своей головой
для разнообразия подумаешь?

Сигналы в Unix не ставятся в очередь (кроме RT-signals, к которым
SIGCHLD не относится). Следовательно при завершении нескольких child-
процессов parent-process может получить только один SIGCHLD, а не
по одному SIGCHLD на каждый завершившийся child.
Например ты заблокировал SIGCHLD и пока он был заблокирован несколько
child-процессов закончились. После разблокирования SIGCHLD ты вполне
возможно получишь сигнал только один раз (и соответственно твой
handler будет вызван только один раз).

Это проиводит к необходимости делать wait*() не просто один раз,
а в цикле до тех пор, пока он не вернет -1 -типа нет больше
завершившихся child-процессов.
И тут подходит именно waitpid() потому, что он умеет ждать
неблокирующим образом при помощи WNOHANG. А wait() не умеет.

Типа: while (waitpid(-1, &status, WNOHANG) != -1);

При этом тебе не надо знать "какой именно ребенок погиб,
чтобы вызвать waitpid именно для него" - ставь -1 вместо PID.

Короче man waitpid и info libc signal

HTH








Onanim
()
Ответ на: комментарий от anonymous

> Было бы интересно узнать, что такое "XSI-compliance option",

Это расширение POSIX для совместимости с Single Unix Specification.

Вообще, игнорировать SIGCHLD _почти_ безопасно, поскольку большинство из работающих на сегодняшний день Юниксов не будут плодить зомби при этом (хотя я лично так никогда не делаю).

Что _не_ безопасно, это при игнорировании SIGCHLD вызывать wait*() и (что еще более тоскливо) getrusage(). Поведение этих вызовов будет вообще непредсказуемо, а в Линуксе отлично от всех стандартов.

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

> Что _не_ безопасно, это при игнорировании SIGCHLD вызывать wait*() и (что еще более тоскливо) getrusage(). Поведение этих вызовов будет вообще непредсказуемо, а в Линуксе отлично от всех стандартов.

http://www.opengroup.org/onlinepubs/009695399/functions/wait.html

---cut---
[XSI] [Option Start] If the calling process has SA_NOCLDWAIT set or has SIGCHLD set to SIG_IGN, and the process has no unwaited-for children that were transformed into zombie processes, the calling thread shall block until all of the children of the process containing the calling thread terminate, and wait() and waitpid() shall fail and set errno to [ECHILD]. [Option End]
---cut---

в чем в сущьности состоит криминал?

// wbr

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

> в чем в сущьности состоит криминал?

Даже то, что ты процитировал, к Линуху не относится: при игнорировании SIGCHLD wait*() НЕ кончается неудачно, а ведет себя так, как будто SIGCHLD не игнорируется.

А это только один из стандартов, к тому же сравнительно недавних!

А getrusage() при RUSAGE_CHILDREN в Линухе вообще противоречит POSIX'у (если SIGCHLD игнорируется).

Die-Hard ★★★★★
()
Ответ на: комментарий от klalafuda

> в чем в сущьности состоит криминал?

Криминал IHMO состоит именно в Linux'е, а точнее в том,
что при SIGCHLD установленном в SIG_IGN waitpid()/wait()
ведут себя не так, как описано в SUSv2:

$ man 2 wait
...
The Single Unix Specification describes a flag SA_NOCLDWAIT (not
supported under Linux) such that if either this flag is set, or the
action for SIGCHLD is set to SIG_IGN then children that exit do not
become zombies and a call to wait() or waitpid() will block
until all children have exited, and then fail with errno set to
ECHILD.

The original POSIX standard left the behaviour of setting SIGCHLD
to SIG_IGN unspecified. Later standards, including SUSv2 and POSIX
1003.1-2001 specify the behaviour just described as an XSI-compliance
option. Linux does not conform to the second of the two points
just described: if a wait() or waitpid() call is made while SIGCHLD
is being ignored, the call behaves just as though SIGCHLD
were not being igored, that is, the call blocks until the next child
terminates and then returns the PID and status of that child.
...

Такая же фигня и с getrusage (man 2 getrusage).

Может теперь Linux исправился и соответствует... но осадок-то остался :-)))

HTH

Onanim
()
Ответ на: комментарий от Die-Hard


О! Пока писал ответ ты уже сам отписал. Сорри.

Onanim
()
Ответ на: комментарий от Die-Hard

> при игнорировании SIGCHLD wait*() НЕ кончается неудачно, а ведет себя так,
> как будто SIGCHLD не игнорируется.

по-моему, очень разумное и правильное поведение.
очень просто было бы добавить в do_wait()

        if (current->sighand->action[SIGCHLD-1].sa.sa_handler == SIG_IGN)
                return -EWHATEVER;

это не было сделано нарочно. я даже и не подозревал, что
это может противоречить стандартам :)

> А getrusage() при RUSAGE_CHILDREN в Линухе вообще противоречит POSIX'у
> (если SIGCHLD игнорируется).

а что должно быть? в linux getrusage() просто не обращает
внимания на установку обработчика для SIGCHLD.

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

2idle:

> ...по-моему, очень разумное и правильное поведение.

Кто ж спорит!

Только другие системы себя иначе ведут :(

> в linux getrusage() просто не обращает внимания на установку обработчика для SIGCHLD.

Согласно ману обращает:

man 2 getrusage

On Linux, if the disposition of SIGCHLD is set to SIG_IGN then the resource usages of child processes are automatically included in the value returned by RUSAGE_CHILDREN, although POSIX 1003.1-2001 explicitly prohibits this.

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

> On Linux, if the disposition of SIGCHLD is set to SIG_IGN then the resource usages of child processes are automatically included in the value returned by
> RUSAGE_CHILDREN, although POSIX 1003.1-2001 explicitly prohibits this.

так это же и означает, что не обращает внимания, нет?

а что должно быть если установлен handler для SIGCHLD, тогда
'resource usages of child' не должны быть 'automatically included
in the value returned by RUSAGE_CHILDREN' ?

или я совсем запутался? (у меня man за 2001 год)

держу все же пари, что не обращает, специально сейчас
посмотрел в код.

кстати, я похоже соврал про "разумно и правильно". я
сейчас не могу это проверить, но если я понимаю код
правильно, то при SIG_IGN wait4() ничего полезного
не вернет, а просто будет блокирован до смерти потомка,
а потом -ECHLD.

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

> так это же и означает, что не обращает внимания, нет?

Но должен!

> а что должно быть если установлен handler для SIGCHLD, тогда 'resource usages of child' не должны быть 'automatically included in the value returned by RUSAGE_CHILDREN' ?

Если SIGCHLD не игнорируется, то для RUSAGE_CHILDREN добавляются ресусы, скушанные только теми детками, которые уже померли. Которые еще живы и кушают дальше, не учитываются.

Если SIGCHLD игнорируется, то для RUSAGE_CHILDREN добавляются ресусы, которые все детки погрызли, не только помершие, но и живые. А POSIX 1003.1-2001 такое запрещает.

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

> Но должен!

опять-таки, проверить не могу, но в linux учитываются
только завершившиеся потомки, независимо от установки
SIGCHLD, т.е. всегда первый случай.

но запутался я теперь окончательно. если POSIX второй
случай запрещает, то это и означает, что SIGCHLD должен
игнорироваться, и linux здесь прав ???

или я мало водки выпил?

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

> Если SIGCHLD игнорируется, то для RUSAGE_CHILDREN добавляются ресусы, которые все детки погрызли, не только помершие, но и живые. А POSIX 1003.1-2001 такое запрещает.

я бы уточнил: не запрещает, а указывает совершенно противоположное поведение:

http://www.opengroup.org/onlinepubs/009695399/functions/getrusage.html

---cut---
The getrusage() function shall provide measures of the resources used by the current process or its terminated and waited-for child processes. If the value of the who argument is RUSAGE_SELF, information shall be returned about resources used by the current process. If the value of the who argument is RUSAGE_CHILDREN, information shall be returned about resources used by the terminated and waited-for children of the current process. If the child is never waited for (for example, if the parent has SA_NOCLDWAIT set or sets SIGCHLD to SIG_IGN), the resource information for the child process is discarded and not included in the resource information provided by getrusage().
---cut---

надуюсь, LSB хоть как-то повлияет на этих ревлюциёнеров :-/

// wbr

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

> опять-таки, проверить не могу, но в linux учитываются
только завершившиеся потомки, независимо от установки
SIGCHLD, т.е. всегда первый случай.

что, в принципе, было бы логично с точки зрения реализации..

> или я мало водки выпил?

ждем, что ответит Die-Hard :)

// wbr

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

> опять-таки, проверить не могу, но в linux учитываются
> только завершившиеся потомки, независимо от установки
> SIGCHLD, т.е. всегда первый случай.

похоже, второй раз соврал.

учитываются-то они действительно независимо от SIGCHLD,
но только те, которые были "утилизованы" через wait4.
т.е. таки это зависит от этого долбаного сигнала.
ладно, завтра в третий раз код посмотрю, и снова поменяю
свое мнение.

вообще-то, последний раз функцию k_getrusage() правил я.
теперь понимаете, почему в linux столько багов?

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

> учитываются-то они действительно независимо от SIGCHLD,

тьфу, блин... хотел сказать, учитываются только
завершившиеся, и независимо от нынешнего состояния
SIGCHLD.

anonymous
()
Ответ на: комментарий от Die-Hard

Ну блин вы разошлись :-)))
Я хотел из любопытства проверить, сравнить с Solaris и AIX
но потом лень стало ;-) Все равно установка SIGCHLD в SIG_IGN людьми
в здравом уме не применяется (ну за исключением программ для одной-
единственной машины).
Плохая карма у этого дела - то семантика в разных системах отличалась,
то POSIX оставлял ее undefined, Linux вот теперь накосячил с wait()
и getrusage()...

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