The OpenNET Project / Index page

[ новости /+++ | форум | теги | ]



"Завершение дочерних процессов 2 уровня"
Вариант для распечатки  
Пред. тема | След. тема 
Форум Программирование под UNIX (Shell скрипты)
Изначальное сообщение [ Отслеживать ]

"Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (0), 13-Май-20, 01:56 
Подскажите, как лучше его организовать? Ситуация следующая: дети запускаются фоном, после чего они рождают ещё детей. Мне нужно всех их вырезать, потому что, если их не прибить собственноручно, они остаются жить навсегда. Добился нужного через pkill -g $$ в конце (повесил на выход), но возникают определённые подозрения (в частности в связи с тем, что при самоубийстве в баше не появляется приглашение, видимо фишка баша для провисших дескрипторов) или же вообще ломается любой ввод (он не отображается). Я так понял, это вообще проблема, в линуксе нельзя просто взять и узнать, кого мы родили. Мне только pstree -p $bgjobpid показывает, что там кто-то где-то висит во внучках (он обходит всех на предмет родителей?), разбирать выхлоп pstree чёт видится извратом. Вообще, в интернете обещали и что pkill -P $$ будет достаточно, да только дети детей то остаются!

Суть дела: мне нужно убить всех детей вместе с их детьми средствами, доступными родителю, в идеале получить перечень пидов и их перебить. Я могу получить пид мейна, скажем, через ppid/pgrp/tpgid, или даже того, кто запускал (баш) из sid, но я не могу получить перечень порождённых процессов и желательно перебить их всех по цепочке? Если не останавливать фоновый процесс через прямое убийство (что я делал изначально, поскольку я прекрасно вижу его в мейне), он вместе со всеми порождёнными (уже не видимыми мне) им переходит под инит при завершении. Если останавливать, порождённые им процессы остаются висеть (под инитом). Пробовал уже по-всякому, и kill, и pkill, и всё остальное, но внучки остаются недосягаемыми.

Из информации, полученной со стаковерфлоу, я сделал вывод, что единственный выход тут, это использовать неймспейс (и грохать его). Так ли это? Как же живут пользователи других систем?

И я смотрю unshare с --kill-child=sigkill как-то странно реагирует на ^C -- я так понимаю ему прилетает kill и sigint не доходит до приложения, в следствии чего я не могу обработать этот кейс в коде -- всё слишком быстро умирает. Или даже не так, но умирает всё равно раньше, чем я успеваю почистить файлы в перехватчике int. А с другими сигналами kill-child (term,int), всё умирает, но приглашение не появляется. Т.е. неймспейсы тут не подходят.

Это конечно хорошо, что мой код работает, но плохо, что я его не понимаю. Чем мне грозит pkill -g $$ на практике? Видимых проблем я не вижу, всё в полном порядке, вот только провисшие дескрипторы меня пугают.

Ответить | Правка | Cообщить модератору

Оглавление

Сообщения [Сортировка по времени | RSS]


1. "Завершение дочерних процессов"  +/
Сообщение от Аноним (0), 13-Май-20, 03:02 
Что-то не то с порядком исполнения, или же временем? Если на exit повешено несколько действий, прилетает sigterm. Если там один pkill -g $$, всё нормально завершается. повесил новую ловушку на выход в ловушке на выход. Что-то странное, я всё чаще начинаю замечать, что не понимаю, почему мой баш работает и как он это делает.
Ответить | Правка | Наверх | Cообщить модератору

2. "Завершение дочерних процессов"  +1 +/
Сообщение от Аноним (2), 13-Май-20, 07:19 
Да тебе бы сценарии к триллерам писать, а не вот это вот всё) ))
Ответить | Правка | Наверх | Cообщить модератору

3. "Завершение дочерних процессов"  +1 +/
Сообщение от eRIC (ok), 13-Май-20, 13:32 
предлагаю название темы поменять, потому-что по таким словам как: "убийство внучек", "суицид" ресурс OpenNet не забанили
Ответить | Правка | Наверх | Cообщить модератору

20. "Завершение дочерних процессов"  +/
Сообщение от Сейд (ok), 05-Июн-20, 20:37 
Поменяли, но внизу на главной странице название почему-то осталось: https://i.imgur.com/yD5x4Dz.png
Ответить | Правка | Наверх | Cообщить модератору

4. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (4), 13-Май-20, 14:39 
> Ситуация следующая: дети запускаются фоном, после чего они рождают ещё детей.

Породив внуков, дети завершаются или остаются жить? Тут нужно либо обучить детей передавать прилетающие SIGTERM'ы и SIGINT'ы внукам (см. встроенные в bash команды trap и jobs), либо как-то передавать список внуков родителю.

> что единственный выход тут, это использовать неймспейс (и грохать его).

В Linux ещё control groups, и они, как мне представляется, более подходят к данному случаю.

Ответить | Правка | Наверх | Cообщить модератору

5. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (0), 13-Май-20, 17:22 
Они живут пока мамка жива, если мейн сворачивается по любой из причин внучки должны быть завершены сразу после детей (чтобы детям от них данные не попали и не было гонки). С внучками ещё проблема в том, что они даже не баш и не могут реагировать на изменения предка.

Я попробовал навесить трапов на фоновый жоб, так я всё равно не могу узнать кого мы родили и там! И начинается вообще какая-то дичь, которую я не могу контролировать (сейчас хотя бы порядок срабатывания обработчиков не нарушается, всё разруливается в мейне имеющем все необходимые данные). У меня нет доступа в детях к внучкам, потому что дети ждут пока внуки завершатся или умрут (это даже не важно, что из двух) и это событие тригеррит детей, которые после этого обрабатывают полученные данные и взаимодействуют с мейном (через файл на диске, угу).

Я так понимаю для работы с cgroups мне понадобится модификация системы и суидные рутовые бинарники? Потому что неймспейсы могут быть пользовательскими (чем весь софт вроде браузеров пользуется и суидные песочницы это вроде как уже не модно), а cgroups от пользователя можно как-то управлять исключительно через systemd,

Ответить | Правка | Наверх | Cообщить модератору

6. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (4), 13-Май-20, 20:38 
> У меня нет доступа в детях к внучкам, потому что дети ждут пока внуки завершатся или умрут

Дети — bash? Внуков можно запускать в фоновом режиме (команда &), тогда доступ к ним остаётся. Также можно ждать завершения фоновых процессов встроенной командой wait.

Bash, кстати, при получении SIGTERM'а автоматически передаёт его всем фоновым потомкам.

> Я попробовал навесить трапов на фоновый жоб, так я всё равно не могу узнать кого мы родили и там!

jobs выдаёт список фоновых процессов, не?

> Я так понимаю для работы с cgroups мне понадобится модификация системы и суидные рутовые бинарники?

Достаточно systemd-run или пользовательской сессии systemd. Возможно, эту всю скриптоту удобнее писать не на bash'е, а на юнитах systemd.

Ответить | Правка | Наверх | Cообщить модератору

7. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (0), 13-Май-20, 21:19 
Вот пример кода:

EXBGFILE=$(mktemp -p /dev/shm/ --suffix=wdfile)

sendvalue() {
  echo "${1}">${EXBGFILE}
}
readvalue() {
  echo "$(<${EXBGFILE})"
}
sendvalue 0

bgloop() {
  while sleep 9 & wait; do
    echo "exec"
    var=$(readvalue)
    echo "${FUNCNAME} read:${var}"
  done
}

bgloop &
bgjob=$!
trap "kill '$bgjob'; rm -v -- '${EXBGFILE}'" EXIT

echo `jobs -l`
echo `jobs -p`
sendvalue 2
sleep 10
sendvalue 5
sleep 10
sendvalue 9
sleep 10
sendvalue 11
echo done

Если я посылаю ^C скрипту, sleep 9 переходит под инит до завершения (kill останавливает только фоновый жоб и sleep никак не остановить). Сейчас я вешаю такую конструкцию на завершение мейна, чтобы убить себя, и при этом прилетало и внучке. У меня есть ощущение, что лучше обойтись без самоубийства (остановки группы процессов, к которой принадлежат все порождённые процессы включая мейн).

trap "kill '$bgjob'; rm -v -- ${EXBGFILE}; trap 'pkill -g $$' EXIT;" EXIT;

При этом kill '$bgjob' (как и jobs -p в мейне) вообще не надёжная тема, процесса может и не оказаться, если мы дёргаем sigint, и тогда килл жалуется, мол, но сач процесс. Однако, pkill -g $$ всегда завершает всех без эксцессов (при таком использовании -- если в trap exit что-то постороннее, прилетает terminated).

Ответить | Правка | Наверх | Cообщить модератору

8. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (0), 13-Май-20, 21:24 
Ой я имел в виду у меня конечно sigint отдельно, всё равно после завершения остаются висеть под мейном. Я запустил этот пример, и у меня слипы плодятся несколько раз, но последний переходит под инит и висит до завершения и вот он-то мне и нужен исчезнувшим сразу.
Ответить | Правка | Наверх | Cообщить модератору

9. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (0), 13-Май-20, 21:25 
Нет, со слипами всё в порядке. А вот по завершении висеть под инитом последний слип дочки (он же внучка) остаётся.
Ответить | Правка | Наверх | Cообщить модератору

10. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (4), 13-Май-20, 21:55 
Нужно сделать ещё один trap в bgloop():

#!/usr/bin/env bash
trap 'kill %' EXIT

bgloop() {
    trap 'kill %' EXIT
    while sleep 10 & wait; do
        :
    done
}
bgloop &
wait


Так при прибитии родителя прибиваются также все дети.
Ответить | Правка | К родителю #7 | Наверх | Cообщить модератору

11. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (0), 13-Май-20, 22:25 
Похоже, то что нужно, спасибо. Только всё ещё не понятно, почему $bgjob и jobs -p сообщают о процессе, который не существует с точки зрения kill при sigint. Он исчезает из-за sigint? И как мне его останавливать тогда, если для мейна его уже нет из-за sigint? Он может и быть, а может и не быть. Неприятненько, куда лучше, когда код без плавающих багов.
Ответить | Правка | Наверх | Cообщить модератору

13. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (4), 14-Май-20, 12:11 
> почему $bgjob и jobs -p сообщают о процессе, который не существует с точки зрения kill при sigint.
> Он может и быть, а может и не быть..

Сейчас проверил, своим потомкам, если это не внешние программы, bash пересылает сигналы завершения сам автоматически, т.е. в коде #10 первый trap излишен, а $bgjob из #7, видимо, был прибит до вызова kill.

> Если отправлять pkill -g $$ в мейне, то bgloop получает только int (не term) и до обработчика exit дело не доходит.

trap ... EXIT срабатывает и на INT (который также прилетает по ctrl+c), и на TERM.

> смерть не мгновенная?

Естественно: используемые сигналы можно перехватить и обработать. Нельзя обработать KILL, SEGV и некоторые другие.

Ответить | Правка | Наверх | Cообщить модератору

14. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (0), 14-Май-20, 17:14 
> Сейчас проверил, своим потомкам, если это не внешние программы, bash пересылает сигналы
> завершения сам автоматически, т.е. в коде #10 первый trap излишен, а
> $bgjob из #7, видимо, был прибит до вызова kill.

1 trap там не излишен, он вообще не работает -- bgloop переходит под инит и остаётся висеть. Он должен быть заменён на

bgloop &
trap "kill $!" EXIT

Тогда работает, но только если bgloop остановлен kill (sigterm) в мейне. Если bgloop прерывается sigint (что происходит не каждый раз)

>> Если отправлять pkill -g $$ в мейне, то bgloop получает только int (не term) и до обработчика exit дело не доходит.
> trap ... EXIT срабатывает и на INT (который также прилетает по ctrl+c),
> и на TERM.

срабатывает, только exit отдельно стрелял после int при нажатии ^C, теперь только на int. Я уже сталкивался с тем, что простые примеры ведут себя не так, как чуть более сложные (из-за разного времени реакции системы надо полагать)

>> смерть не мгновенная?
> Естественно: используемые сигналы можно перехватить и обработать. Нельзя обработать KILL,
> SEGV и некоторые другие.

Дело не в обработке, я опасаюсь, что возникнет гонка из-за задержки между отправкой сигнала и реакцией на него. В примере из #10 bgloop дети переходят под мейн и продолжают работать бесконечно . И мне не надо bgloop& wait, мне надо чтобы он работал параллельно, в #10 мы в мейне ждём завершения фонового процесса, которое не случится пока мы не прервём. Мейн должен работать и передавать данные в bgloop, я ведь не зря привёл такой пример в #7.

Ответить | Правка | Наверх | Cообщить модератору

15. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (4), 14-Май-20, 20:25 
> И мне не надо bgloop& wait, мне надо чтобы он работал параллельно, в #10 мы в мейне ждём завершения фонового процесса, которое не случится пока мы не прервём.

В #10 главный скрипт завершается до завершения bgloop'а, в этом проблема. Мэйн должен либо что-то делать, либо ждать завершения детей, но не завершаться сам. Можно запихнуть wait в конец, после кормёжки детей данными, это спасёт от состояния гонки.

Ответить | Правка | Наверх | Cообщить модератору

16. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (0), 15-Май-20, 20:05 
Поэтому я и пытаюсь их прибить до выхода, но я даже не знаю кого. Думал на тему того, чтобы передавать пиды внучек через диск. но что-то и так уже слишком много файлов генерирую. Попробовал повесить wait на sigexit в мейне, что-то эксперименты не увенчались успехом и bgloop замечательно продолжает жить отдельно после нормального завершения мейна. Но sigint останавливает, это да.
Ответить | Правка | Наверх | Cообщить модератору

17. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Licha Morada (ok), 15-Май-20, 21:19 
> Поэтому я и пытаюсь их прибить до выхода, но я даже не
> знаю кого.

Можно поддержиавать в актуальном состоянии список всех детей.
После каждого порождения, добавлять его PID в список:
CHILDERN_PIDS="$CHILDERN_PIDS $!"
https://stackoverflow.com/questions/2618403/how-to-kill-all-...

Можно узнавать список "всех детей" непосредственно перед прибиванием.
CHILDERN_PIDS=$(ps -o pid= --ppid $$)

Потом по CHILDERN_PIDS можно итерировать в простом цикле for.
Делать отдельно в каждом поколении в отношении непосредственных детей, либо рекурсивно из "дедушки".
Тут хорошо описанно:
https://unix.stackexchange.com/questions/124127/kill-all-des...

Должно работать если:
1. Дети есть строго дети, в терминах иерархии процессов, а не демонизированные сироты.
2. Дети успевают сделать что-то осмысленное после того как их прибивают и до, собственно, умирания.
Рекурсия из дедушки, в отличии от отдельной итерации в каждом поколении, смягчает ограничение 2.


> Думал на тему того, чтобы передавать пиды внучек через
> диск. но что-то и так уже слишком много файлов генерирую.

Не такой уж и порочный путь. Если написать некий диспетчер для отслеживания всего дерева, то можно будет отличать служебные файлы от временных данных и бардак станет более контролируемым.


Ответить | Правка | Наверх | Cообщить модератору

18. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (4), 19-Май-20, 02:11 
> sigexit

Нет такого сигнала. EXIT — это обобщение bash'а для обработки сигналов, по которым он должен завершаться, а также нормального его завершения.

Но я не пойму, зачем вешать wait в trap, когда его можно разместить в конце программы.

Ответить | Правка | К родителю #16 | Наверх | Cообщить модератору

12. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от Аноним (0), 13-Май-20, 22:57 
Заметил что при таком использовании работает корректно, только если в bgloop прилетают оба сигнала (sigint и sigkill), если kill $bgpid не отправлять из мейна (выходе), то фоновый процесс останется висеть и вместе с внучками перейдёт под инит. Или он может остановится sigint, и тогда из мейна его уже не убить на выходе. Если отправлять pkill -g $$ в мейне, то bgloop получает только int (не term) и до обработчика exit дело не доходит. Кроме того, 1 раз я успел заметить, что внучка перед смертью переходит под инит (в принципе это не плохо), это значит смерть не мгновенная?
Ответить | Правка | К родителю #10 | Наверх | Cообщить модератору

19. "Завершение дочерних процессов 2 уровня"  +/
Сообщение от user user (?), 20-Май-20, 15:24 
чисто из любопытства, какой сценарий привел победе fork на pthread_create?
Ответить | Правка | Наверх | Cообщить модератору

Архив | Удалить

Рекомендовать для помещения в FAQ | Индекс форумов | Темы | Пред. тема | След. тема




Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2024 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру