PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : C++: laufendes Programm gibt Shell frei?



RoCMe
19-05-2007, 21:30
Hi!

ich bin ziemlich unerfahren, was C++ angeht, also seit nicht ganz so streng mit mir ;)

Ich schraube gerade an einer Art "Wecker" für die Komandozeile. Ziel ist es, durch Aufruf eines Kommandos nach einer bestimmten Zeit an etwas errinnert zu werden, ich vergess nämlich immer meine Pizza im Ofen ;-(. Sicher, so etwas gibt es bestimmt schon 100x, aber meins soll halt ganz besonders toll werden ;) (na gut, mir ist halt nichts besseres eingefallen :-/ )

Jedenfalls habe ich jetzt ein Programm das die Eingaben einliest. und mich zu gegebener Zeit an meine Pizza erinnert.

Allerdings soll mein Programm jetzt nicht die nächsten 20 Minuten (bis meine Pizza fertig ist) meine Shell blockieren. Schöner wäre es doch, wenn das Programm meine Eingaben entgegen nimmt und dann im Hintergrund weiterläuft, bis die Zeit gekommen ist, mich zum essen zu schicken und dann Alarm schlägt...

Hoffe, ich konnte verständlich machen, wo mein Problem liegt ...

gruß,

RoCMe

jeebee
20-05-2007, 10:42
in der shell mit
programmname & aufrufen: schickt den Prozess in den Hintergrund. Allfällige Ausgaben nach stdout/stderr werden immer noch in der Shell angezeigt.

RoCMe
20-05-2007, 11:08
Hm... nur funktioniert dann cin nicht mehr :( Und das benutze ich, um de verschiedenen Werte einzulesen (Titel des Alarm etc).

Ich habe mir noch einmal Gedanken gemacht: Angenomen, ich teile mein Programm in 2 Teilapplikationen , ein "Wecker-Stell-Programm", dass die Daten für einen neuen Alarm einliest, und dann an die 2. Applikation weiterleitet, also an eine Art Dämon, der irgendwo im Hintergrund läuft und zu gegebener Zeit Alarm schlägt.
Dann müsste ich nur noch eine Möglichkeit finden, wie der aufgerufene Dämon laufen kann, ohne dass mein eigentliches Programm weiterlaufen muss.

Das hätte außerdem den Vorteil, dass ich bei einem 2. Alarm nur noch dem schon laufenden Dämon die neuen Daten übergeben müsste, und der könnte dann 2x Alarm schlagen...

Ist das vom Ansatz her sinnvoll? Wenn ja, wie kann ich dann eine Applikation starten, ohne dass sie beim beenden meines Programms mit beendet wird? Ich meine da mal was von Vater-Kind-Prozess gehört zu haben ...

Gruß,

RoCMe

Yonibear
20-05-2007, 13:59
Du kannst das auch einfacher mit dem fork-Aufruf lösen.
fork() kopiert den aktuellen Prozess in einen Kindsprozess und lässt beide weiterlaufen. Am Rückgabewert erkennst du in welchem Prozess du dich befindest.
Im Vaterprozess solltest du die Daten vor dem fork entgegennehmen. Wenn du den Vaterprozess beendest, existiert den Kindprozess weiter, blockiert aber die Konsole nicht und hat daher auch keinen Zugriff auf stdin mehr.

anda_skoa
20-05-2007, 18:31
Du könntest auch mittels "at" dein Alarmprogramm starten, d.h. "at" das Warten überlassen

Ciao,
_

jan61
20-05-2007, 19:28
Moin,


Du könntest auch mittels "at" dein Alarmprogramm starten, d.h. "at" das Warten überlassen

Ciao,
_

Wohin soll denn die Ausgabe des at-Jobs gehen? at ist ein Dämon, der stdout per Mail verschickt. Ein TTY zum Beliefern hat ein Dämon nicht.

Tipp von Yonibear
Du kannst das auch einfacher mit dem fork-Aufruf lösen.
fork() kopiert den aktuellen Prozess in einen Kindsprozess und lässt beide weiterlaufen. Am Rückgabewert erkennst du in welchem Prozess du dich befindest.
Im Vaterprozess solltest du die Daten vor dem fork entgegennehmen. Wenn du den Vaterprozess beendest, existiert den Kindprozess weiter, blockiert aber die Konsole nicht und hat daher auch keinen Zugriff auf stdin mehr. - Was soll das bringen? Da kannst Du auch gleich den Papa in den Hintergrund schicken. Und: Ein per fork() gestarteter Child ist nach dem Abmurksen des Papas nicht unbedingt ein Dämon (das muss ihm gesagt werden) sondern ein Zombie, d. h. ein verwaistes Kind, dass seinen Returncode nicht mehr los wird, weil der Papa verreckt ist (der Prozess, der fork() aufruft, muss im Normalfall den RC seiner child-Prozesse per wait() oder waitpid() abfragen, erst dann beenden sich diese und verschwinden aus der Prozesstabelle). Ich bin nicht sicher, ob der Zombie noch Zugriff auf stdout hat - ich glaube eher nicht, aber nach einer Weile - und mehreren Aufträgen - wirst Du feststellen, dass sich ebensoviele Zombie-Prozesse auf Deinem System tummeln. Nicht schädlich, solange nicht die Prozesstabelle des Kernels überschwappt ;)

Ich würde nicht mit C(++)-Kanonen auf Spatzen schießen, sondern das Ganze über ein Shellscript lösen - da geht das nämlich viel einfacher:

1. eine Named Pipe erzeugen
man mknod
2. in einem Shellscript per Endlosschleife diese Named Pipe abfragen und bei ankommenden Eingaben für diese einen Shell-Aufruf generieren, z. B.
sh -c 'sleep `expr Minuten \* 60`; echo "Bier ist kalt"' &
3. Dieses Script per
script & in den Hintergrund schicken

Nun kannst Du mit
echo "Bier ist kalt genug" 10 >/pfad/zur/named/pipe Deine Aufträge abschicken und Dich 10 Minuten später an der Meldung erfreuen, dass Du endlich ein kühles Bierchen genießen kannst.

Jan

Yonibear
20-05-2007, 21:41
Ich hab davon zugegebenermaßen nicht viel Ahnung, aber in einem kurzen Testprogramm hat das alles so funktioniert wie es gefordert war, der Kindprozess hatte Zugriff auf stdout und hat nach dem Beenden auch keinen Zombie hinterlassen.
Beim näheren Hinsehen mit strace fiel mir auf, dass nicht fork nicht mit dem Syscall fork sondern mit clone implementiert wurde.
Bei der Verwendung des laut man-page identischen vfork wird auch tatsächlich vfork aufgerufen, hier wird der Kindsprozess tatsächlich nicht in den Hintergrund geschickt.
Gibts eine vernünftige Erklärung für dieses Verhalten oder gehört das ins Wunderland des undefinierten Verhaltens?

RoCMe
21-05-2007, 12:54
Hey!
Mir ist schon klar, dass ich das einfacher über die Kommandozeile lösen kann (at, xmsg und fertig) aber dann häte ich ja nix gelernt!

Ich versuche ja gerade, meine Java Kenntnisse in C++ Erfahrung umzuwandeln, indem ich kleine Programme schreibe - da nützt mir die Kommandozeile nix ;)

Also, ich hatte das jetzt vor wie oben beschrieben: Daten abfragen, fork(), wenn fork() gleich 0 (dann bin ich im Kindprozess) , dann warte time Sekunden und gib dann die Meldung aus. Alles Käse?



Ein per fork() gestarteter Child ist nach dem Abmurksen des Papas nicht unbedingt ein Dämon (das muss ihm gesagt werden)

Erstmal, warum muss der "Papa" denn abgemurkst werden, beendet der sich nach obigem Vorgehen nicht automatisch? (oder wartet er auf den Cild-Prozess)? Wie erzeuge ich denn so einen Dämon?
Kurzes googeln hat mich nicht weitergebracht, aber wenn ich einen Dämon erzeugen könnte und ihm mitteilen, welche Alarmmeldungen anstehen, hätte ich das Prob auch gelöst, oder nicht? Lediglich die Alarmmeldung müsste ich dann anderswo als in der normalen Konsole vornehmen, aber ein paar beeps() find ich sowieso eindringlicher ;)

danke noch mal für hilfe!

RoCMe

//EDIT: Ein Touchpad ist scheiße, einmal gegen kommen, und der Text ist halb verschwunden :-/

jan61
22-05-2007, 00:17
Mir ist schon klar, dass ich das einfacher über die Kommandozeile lösen kann (at, xmsg und fertig) aber dann häte ich ja nix gelernt!
...
Also, ich hatte das jetzt vor wie oben beschrieben: Daten abfragen, fork(), wenn fork() gleich 0 (dann bin ich im Kindprozess) , dann warte time Sekunden und gib dann die Meldung aus. Alles Käse?
...
Erstmal, warum muss der "Papa" denn abgemurkst werden, beendet der sich nach obigem Vorgehen nicht automatisch? (oder wartet er auf den Cild-Prozess)? Wie erzeuge ich denn so einen Dämon?
Kurzes googeln hat mich nicht weitergebracht, aber wenn ich einen Dämon erzeugen könnte und ihm mitteilen, welche Alarmmeldungen anstehen, hätte ich das Prob auch gelöst, oder nicht? Lediglich die Alarmmeldung müsste ich dann anderswo als in der normalen Konsole vornehmen, aber ein paar beeps() find ich sowieso eindringlicher ;)
...


Aha, jetzt wird mir Deine Intention klar ;-)

Zum Vatermord: Das hatte Yonibear vorgeschlagen, darauf hatte ich mich bezogen.

Zum Thema Dämon:
man daemon

Zum fork(): Wenn Du nach dem fork() im Parent dann einfach ein exit machst, dann isser natürlich weg. Im Allgemeinen sollte er aber die Exitcodes der Children abfragen, damit eben keine verwaisten Kinder zurückbleiben:
man waitpid

@Yonibear: Dass fork() mittels clone() implementiert ist, das kenne ich noch nicht - auf was für einer Distri bist Du denn? clone() unterscheidet sich tatsächlich vom "normalen" fork() - u. a. wird der Child nach Ausführen der übergebenen Funktion beendet und er erbt u. a. die Filedeskriptoren vom Parent, so dass auch nach dessen Beendigung stdout zur Verfügung steht. Näheres in:
man clone

Ich habe mal "fork linux example" in die allwissende Müllhalde eingegeben (also Google ;-) und als 1. Treffer das hier gekriegt:
http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

Jan