Jak czekać na program uruchomiony w innej powłoce

20

Mam program, który wykonuje dużą część pracy (zajmuje około 4-5 godzin), którą uruchamia cron, gdy wszystkie dane, z którymi współpracuje, stają się dostępne. Czasami, kiedy czekam na zakończenie, chciałbym mieć możliwość uruchomienia innego (interaktywnego) programu po jego zakończeniu. połączenie oczekujące wygląda obiecująco, ale będzie czekać tylko na dzieci.

Hildred
źródło
Jedyną inną metodą, jaką mogę sobie wyobrazić, jest utworzenie pliku z cronjob, a następnie użycie inotifywait w tym procesie. Po usunięciu plików można rozpocząć drugi proces (uruchomiony inotifywait).
slm
Myślę, że możesz zrobić coś podobnego, korzystając ipcrównież z komunikacji międzyprocesowej. man ipc.
slm
Chociaż nie oglądasz usługi, aby ją zrestartować, God, Monit lub jeden z innych pakietów wymienionych w tym pytaniu
slm
@slm może być używany w dowolnym systemie plików, na przykład czekać na close_write na / proc / _pid_ / fd / 1?
hildred
Nie do końca pewne, ale może to być inny sposób na zrobienie tego 8-). Było trochę Q, które pamiętam, gdzie była nowa funkcjonalność jądra związana z monitorowaniem procesu podobna do inotifywait (dla plików). Pomyślałem, że ta nowa funkcja dotyczy wydarzeń w toku, ale wiele pytań i odpowiedzi zaczyna działać w mojej głowie 8-). Myślę, że A zostało dostarczone przeze mnie lub Gillesa.
slm

Odpowiedzi:

13

Zdecydowanie wolę rozwiązanie EDIT # 3 (patrz poniżej).

jeśli nie jest w tej samej powłoki użyć while pętlę Warunkiem PS -p powrocie prawdziwe. Położyć spać w pętlę, aby zmniejszyć zużycie procesora.

while ps -p <pid> >/dev/null 2>&1
do
   sleep 10
done 

lub jeśli twój system UNIX obsługuje / proc (na przykład HP-UX nadal nie obsługuje).

while [[ -d /proc/<pid> ]]
do 
    sleep 10
done

Jeśli chcesz przekroczyć limit czasu

timeout=6  # timeout after 1mn  
while ((timeout > 0)) && ps -p <pid> >/dev/null 2>&1
do
   sleep 10
   ((timeout -= 1))
done 

EDYCJA 1

Jest inny sposób: nie używaj crona . Użyj polecenia wsadowego do układania zadań w stos.

Na przykład możesz codziennie układać wszystkie swoje prace. Partię można dostroić, aby umożliwić pewną równoległość, dzięki czemu zablokowane zadanie nie zatrzyma całego stosu (zależy to od systemu operacyjnego).

EDYCJA 2

Utwórz fifo w swoim katalogu domowym:

$ mkfifo ~/tata

pod koniec pracy:

echo "it's done" > ~/tata

na początku innej pracy (tej, która czeka):

cat ~/tata 

To nie odpytywanie, to stare dobre blokowanie IO.

EDYCJA # 3

Za pomocą sygnałów:

Na początku skryptu (ów), który (e) czeka:

echo $$ >>~/WeAreStopped
kill -STOP $$

pod koniec długiej pracy:

if [[ -f ~/WeAreStopped ]] ; then
    xargs kill -CONT < ~/WeAreStopped
    rm ~/WeAreStopped
fi
Emmanuel
źródło
Ankieta, fuj! Cudowna decyzja: marnuj czas procesora lub mój czas na dostrojenie snu. Musi być lepsza odpowiedź.
hildred
:) Odpytywanie jest dla ciebie dobre, odpytywanie jest bezstanowe, odpytywanie jest niezawodne.
Emmanuel,
odpytywanie jest wolne, odpytywanie marnuje czas procesora.
hildred
Przy czasie wykonania 0,01 s 1440 ps wykonane w ciągu 4 godzin zużyłoby 14,4 s. Znacznie mniej niż program zarządzający zależnościami zadań: D
Emmanuel,
Myślę, że jest to prawdopodobnie najlepsza opcja: stackoverflow.com/questions/1058047/… , nawet jeśli jest zhackowana.
slm
5

Możesz zmodyfikować swoje zadanie cron, aby użyć flagi.

Zamiast

2  2 * * *           /path/my_binary

Możesz użyć

2  2 * * *           touch /tmp/i_m_running; /path/my_binary; rm /tmp/i_m_running

I po prostu monitoruj ten plik w skrypcie lub nawet ręcznie. Jeśli istnieje, oznacza to, że Twój program działa; w przeciwnym razie możesz robić, co chcesz.

Przykład skryptu:

while [[ -f /tmp/i_m_running ]] ; do
   sleep 10 ;
done
launch_whatever_you_want

Jeśli nie chcesz używać sleep, możesz zmodyfikować skrypt i uruchamiać go przez cron raz na X minut.

W takim przypadku przykładowym skryptem będzie:

[[ -f /tmp/i_m_running ]] && { echo "Too early" ; exit ; }
launch_whatever_you_want

W ten sposób jest trochę łatwiej, ponieważ nie musisz znajdować PID procesu cron.

pośpiech
źródło
4

Nie ma możliwości, aby proces czekał na zakończenie innego procesu, z wyjątkiem sytuacji, gdy rodzic czeka na zakończenie jednego z procesów potomnych. Jeśli możesz, uruchom program za pomocą skryptu:

do_large_amount_of_work
start_interactive_program

Jeśli nie możesz tego zrobić, na przykład przed rozpoczęciem dużej ilości pracy z zadania cron, ale programu interaktywnego z kontekstu sesji, zrób to

do_large_amount_of_work
notify_completion

Istnieje kilka sposobów wdrożenia notify_completion. Niektóre środowiska graficzne zapewniają mechanizm powiadamiania ( otworzyć okno na wyświetlaczu zdalnego X (dlaczego „nie można otworzyć ekran”)? Może być przydatne). Możesz także zrobić to za pomocą powiadomień o zmianie pliku. W systemie Linux funkcja powiadamiania o zmianie pliku jest niedostępna .

do_large_amount_of_work
echo $? >/path/to/finished.stamp

Aby zareagować na utworzenie /path/to/finished.stamp:

inotifywait -e close_write -q /path/to/finished.stamp
start_interactive_program

Jeśli nie możesz zmienić sposobu, w jaki do_large_amount_of_workjest wywoływany, ale wiesz, który plik modyfikuje jako ostatni, możesz użyć tego samego mechanizmu, aby zareagować, gdy plik zostanie zamknięty. Możesz także reagować na inne zdarzenia, takie jak zmiana nazwy pliku ( inotifywaitlista możliwości znajduje się w instrukcji obsługi).

Gilles „SO- przestań być zły”
źródło
0

Wywołanie skryptu przez cronjob wywołuje pusty skrypt powłoki, do którego można wstawiać kolejne zadania, jeśli są potrzebne.

Jest to bardzo podobne do podejścia Gillesa.

cronjob-task.sh zawiera:

# do_large_amount_of_work

./post-execute.sh

gdzie post-execute.shjest zwykle puste, chyba że widzisz, że musisz uruchomić kolejne zadanie.

Daniel F.
źródło