Wie warte ich auf ein Programm, das in einer anderen Shell gestartet wurde?

20

Ich habe ein Programm, das einen großen Teil der Arbeit erledigt (dauert ungefähr 4-5 Stunden), das von cron gestartet wird, wenn alle Daten, mit denen es arbeitet, verfügbar werden. Manchmal, wenn ich darauf warte, dass es zu Ende ist, möchte ich, dass ein anderes (interaktives) Programm startet, wenn es zu Ende ist. Der Warteanruf sieht vielversprechend aus, wird aber nur auf Kinder warten.

hildred
quelle
Die einzige andere Methode, die ich mir vorstellen kann, ist, eine Datei aus cronjob zu erstellen und dann inotifywait für diesen Prozess zu verwenden. Wenn die Dateien gelöscht werden, kann Ihr zweiter Prozess (inotifywait ausführen) beginnen.
slm
Ich denke, Sie könnten etwas in diese Richtung tun, indem Sie ipcauch Interprozesskommunikation verwenden. man ipc.
slm
Auch wenn Sie keinen Dienst zum Neustarten überwachen, erledigen Gott, Monit oder eines der anderen in dieser Frage und Antwort genannten Pakete den Job: unix.stackexchange.com/questions/75785/…
slm
@slm kann inotify auf jedem Dateisystem verwendet werden, zum Beispiel auf close_write auf / proc / _pid_ / fd / 1 warten?
Hildred
Nicht ganz sicher, aber das könnte eine andere Möglichkeit sein. Es gab einige Fragen, an die ich mich erinnere, als es einige neue Kernelfunktionen im Zusammenhang mit der Prozessüberwachung gab, ähnlich wie bei inotifywait (für Dateien). Diese neue Funktion war für Events in Bearbeitung, ich dachte, aber viele der Fragen und Antworten laufen in meinem Kopf zusammen. 8-). Ich denke, das A wurde von mir oder Gilles zur Verfügung gestellt.
slm

Antworten:

13

Ich bevorzuge definitiv die EDIT # 3- Lösung (siehe unten).

Wenn es sich nicht in derselben Shell befindet, verwenden Sie eine while- Schleife mit der Bedingung ps -p, die true zurückgibt . Setzen Sie einen Schlaf in die Schleife, um die Prozessorauslastung zu reduzieren.

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

oder wenn Ihr UNIX / proc unterstützt (z. B. HP-UX immer noch nicht).

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

Wenn Sie eine Auszeit wünschen

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

EDIT # 1

Es gibt einen anderen Weg: Verwenden Sie kein Cron . Verwenden Sie den Batch - Befehl , um Ihre Aufträge zu stapeln.

Zum Beispiel könnten Sie täglich alle Ihre Jobs stapeln. Der Stapel kann so optimiert werden, dass eine gewisse Parallelität besteht, sodass ein blockierter Job nicht den gesamten Stapel stoppt (dies hängt vom Betriebssystem ab).

EDIT # 2

Erstellen Sie ein FIFA in Ihrem Home-Verzeichnis:

$ mkfifo ~/tata

am Ende deines Jobs:

echo "it's done" > ~/tata

zu Beginn des anderen Jobs (derjenige, der wartet):

cat ~/tata 

Es ist keine Abfrage, es ist alt, gut, IO zu blockieren.

EDIT # 3

Signale verwenden:

Zu Beginn des Skripts:

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

am ende deiner langen arbeit:

if [[ -f ~/WeAreStopped ]] ; then
    xargs kill -CONT < ~/WeAreStopped
    rm ~/WeAreStopped
fi
Emmanuel
quelle
Umfrage, yuck! Schöne Entscheidung: Verschwenden Sie Prozessorzeit oder meine Zeit, um den Schlaf zu optimieren. Es muss eine bessere Antwort geben.
Hildred
:) Polling ist gut für Sie, Polling ist zustandslos, Polling ist zuverlässig.
Emmanuel
Das Polling ist langsam, das Poling verschwendet Prozessorzeit.
Hildred
Bei einer Ausführungszeit von 0,01 s hätten die während der 4 Stunden ausgeführten 1440 ps 14,4 s verbraucht. Viel weniger als ein
Emmanuel
Ich denke, dies ist wahrscheinlich die beste Option: stackoverflow.com/questions/1058047/… , obwohl es hacky ist.
slm
5

Sie können Ihren Cron-Job so ändern, dass er ein Flag verwendet.

Anstatt

2  2 * * *           /path/my_binary

Sie können verwenden

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

Und überwachen Sie diese Datei einfach im Skript oder sogar manuell. Wenn es existiert, läuft Ihr Programm. Ansonsten können Sie tun, was Sie wollen.

Das Skriptbeispiel:

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

Falls Sie es nicht verwenden sleepmöchten, können Sie das Skript ändern und es einmal pro X Minuten über cron ausführen.

In diesem Fall lautet das Skriptbeispiel:

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

Dieser Weg ist etwas einfacher, da Sie die PID Ihres Cron-Prozesses nicht finden müssen.

eilen
quelle
4

Es gibt keine Möglichkeit, dass ein Prozess auf den Abschluss eines anderen Prozesses wartet, außer dass ein Elternteil auf den Abschluss eines seiner untergeordneten Prozesse wartet. Wenn Sie können, starten Sie das Programm über ein Skript:

do_large_amount_of_work
start_interactive_program

Wenn Sie das beispielsweise nicht können, bevor Sie die große Menge an Arbeit von einem Cron-Job, aber dem interaktiven Programm aus dem Kontext Ihrer Sitzung heraus starten möchten, nehmen Sie dies vor

do_large_amount_of_work
notify_completion

Es gibt verschiedene Möglichkeiten zur Implementierung notify_completion. Einige Desktop-Umgebungen bieten einen Benachrichtigungsmechanismus ( Öffnen eines Fensters auf einer Remote-X-Anzeige (warum "Anzeige kann nicht geöffnet werden"?) Kann hilfreich sein). Sie können auch eine Benachrichtigung über Dateiänderungen erstellen. Unter Linux ist die Benachrichtigungsfunktion für Dateiänderungen inotify .

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

Um auf die Schaffung von zu reagieren /path/to/finished.stamp:

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

Wenn Sie die Art des do_large_amount_of_workAufrufs nicht ändern können , aber wissen, welche Datei zuletzt geändert wurde , können Sie auf dieselbe Weise reagieren, wenn diese Datei geschlossen wird. Sie können auch auf andere Ereignisse wie das Umbenennen einer Datei reagieren ( inotifywaiteine Liste der Möglichkeiten finden Sie im Handbuch).

Gilles 'SO - hör auf böse zu sein'
quelle
0

Wenn das Skript vom Cronjob ausgelöst wird, rufen Sie ein leeres Shell-Skript auf, in das Sie bei Bedarf Folgeaufgaben einfügen können.

Es ist Gilles 'Ansatz sehr ähnlich.

cronjob-task.sh enthält:

# do_large_amount_of_work

./post-execute.sh

Wo post-execute.shist in der Regel leer, es sei denn, Sie sehen, dass Sie eine Folgeaufgabe auslösen müssen.

Daniel F
quelle