PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Mit Perl ein Programm starten und steuern


Subby
06.11.2007, 17:02
Hi!

Ist folgendes möglich?
Ich habe ein Programm in C, z.B.
int main() {
do {
scanf(x);
print(x)
} while (x != 0);
}
(Stark vereinfacht.)
Also sowas wie eine Eingabeaufforderung


Was ich nun möchte:

Ich möchte dieses Programm mit Perl laden und jederzeit die Möglichkeit haben diesem Programm Eingabe zu übergeben, z.B. "1\n" oder "0\n"

Ich habe es mit Pipes probiert, aber da ist das Problem, dass die Eingabe dem programm erst übergeben wird wenn ich das HANDLE close. Also alles auf einmal oder garnichts.
Ich möchte das Programm aber gerne in meinem Perlscript im Hintergrund laufen haben und jederzeit Eingaben übergeben können.

Hat jemand eine Lösung dafür?

Grüße, Alex


kill4h`
06.11.2007, 17:38
Hmm, das hab ich auch noch nie versucht, aber mal so ein erster Gedanke:
Wenn du mit system() dein C Prog startest, kannst du es ja in den Hintergrund setzen. Vorausgesetzt, dein C Tool liest von der Standardeingabe, kannst du ja auch in Perl einfach da rein schreiben, ich glaube das ist dann <STDOUT> oder evtl sogar einfach mit print.
Was ich allerdings nicht genau weiß ist, ob das Perl Prog weiterläuft. Denn system() ruft ja erst fork() auf und dann exec(). Und normalerweise wartet das, bis dein Subprogramm beendet ist. Evtl. kann man da aber mit Shell Tricks weiterkommen, vllt. das Tool mit einem & am Ende starten oder anderes.

Alamar
06.11.2007, 18:31
Wie wäre es mit selber forken und exec benutzen....

kill4h`
06.11.2007, 19:07
Musst du dann nicht selber waitpid() callen?

Subby
06.11.2007, 20:04
Naja, waitpid soll man ja dann grad nicht callen, sonst wartet er ja wieder.

Aber wie geb ich dem Prozess dann Daten rüber, wenn ich nur seine pid habe?

Alamar
06.11.2007, 20:09
Für waitpid() hat man Signalhandler die aufgerufen wenn man ein entsprechendes Signal bekommt. Hier halt SIGCHLD. Dort ruft man dann ein waitpid() auf.
Aber selbst dass muss man nicht, dann hat man halt einen Zombie entry in der Prozess Tabelle was sich aber spätestens dann wieder auflöst wenn der Parent sich beendet und Ressourcen werden dadurch ja nichtmehr belegt. (Bis auf den ps-table Eintrag)
Du kannst eine Pipe benutzen um Daten zwischen Prozessen auszutauschen.
(IPC eben ;) )

Subby
06.11.2007, 20:25
Für waitpid() hat man Signalhandler die aufgerufen wenn man ein entsprechendes Signal bekommt. Hier halt SIGCHLD. Dort ruft man dann ein waitpid() auf.
Aber selbst dass muss man nicht, dann hat man halt einen Zombie entry in der Prozess Tabelle was sich aber spätestens dann wieder auflöst wenn der Parent sich beendet und Ressourcen werden dadurch ja nichtmehr belegt. (Bis auf den ps-table Eintrag)
Du kannst eine Pipe benutzen um Daten zwischen Prozessen auszutauschen.
(IPC eben ;) )

Kennst da ein kleines Tutorial oder Beispiel?
Im Grund sollen auch keine Daten ausgetauscht werden das Programm das eingaben enthalten soll ist schon fertig und kann nur über stdin Daten erhalten.

Alamar
06.11.2007, 20:53
Tutorial weiß ich keins und Beispiel kann ich dir nur ein zwei Codeschnippsel von mir zeigen.
Buch empfehlung kann ich allerdings aussprechen ;) (Programming Perl von Larry Wall *g)

Signal handler:

#Catching Signals
#executing die will call the "END" function
#which does the cleanup (Closing open files/sockets)
$SIG{INT} = $SIG{TERM} = $SIG{KILL} = $SIG{QUIT} = \&cmd_main_cleanup;
$SIG{HUP} = \&cmd_main_restart;


Forking:

my $pid = fork();
if($pid > 0) { exit 0; }
elsif($pid==0) { }

fork() gibt (siehe perldoc -f fork) an den Parent die PID des Childs zurück.
Wenn also PID > 0 bist du im Parent, wenn PID == 0 bist du im CHILD.
(Im Child kann dann zb stehen "exec myprogram")
Im Parent steht in diesem Fall ein exit aber dort kann auch jeder andere beliebige Code stehen.

kill4h`
06.11.2007, 20:58
Und ich dachte immer, man sollte sowas wie Zombies vermeiden :)

Alamar
06.11.2007, 21:18
kill4h: generell natürlich, aber sie schmerzen nicht weil sie keine Ressourcen brauchen. Unter Unix/Linux läuft das so, wenn du einen Zombie hast (Weil der Parent seine Childs nicht "einsammelt"(wait/waitpid etc. aufruft)) bleiben alle beendeten Childs im state Z (Zombie) in der Prozesstabelle stehen aber brauchen keine weiteren Ressourcen.
Wenn dann der Parent gekillt wird oder irgendwann selbst beendet werden alle nicht eingesammelten (auch "orphaned"/"verwaiste") Kinder von init (dem Prozess mit der ID 1 - der Prozess von dem alle abstammen ;) ) "adoptiert" bzw. einfach verarbeitet indem init für diese verwaisten Childs waitpid aufruft.

Subby
06.11.2007, 21:36
#Catching Signals
#executing die will call the "END" function
#which does the cleanup (Closing open files/sockets)
$SIG{INT} = $SIG{TERM} = $SIG{KILL} = $SIG{QUIT} = \&cmd_main_cleanup;
$SIG{HUP} = \&cmd_main_restart;
Forking:

my $pid = fork();
if($pid > 0) { exit 0; }
elsif($pid==0) { }
fork() gibt (siehe perldoc -f fork) an den Parent die PID des Childs zurück.
Wenn also PID > 0 bist du im Parent, wenn PID == 0 bist du im CHILD.
(Im Child kann dann zb stehen "exec myprogram")
Im Parent steht in diesem Fall ein exit aber dort kann auch jeder andere beliebige Code stehen.



Danke, das Buch habe ich, aber wie ich nun andere Sachen als Kill, Term und Quit an die Anwendung schicke weiß ich eben nicht. Und irgendwie find ich auch nirgends etwas... :(
Ich mein das sind ja alles Signale, aber ich möchte eine Eingabe auf den Stdin des Prozesses legen.

Alamar
06.11.2007, 21:45
Stichwort PIPE schau im INDEX von Programming Perl, habe gerade bei mir geschaut da wird IPC und pipes ab Seite 442 abgehandelt das sollte dir eigentlich eine Vorstellung geben, wie du ein Programm startest und dein STDOUT von diesem als STDIN gelesen wird.

Du kannst dir auch perldoc -f open näher ansehen.

If the filename begins with '|', the filename is interpreted as
a command to which output is to be piped, and if the filename
ends with a '|', the filename is interpreted as a command which
pipes output to us. See "Using open() for IPC" in perlipc for
more examples of this. (You are not allowed to "open" to a
command that pipes both in and out, but see IPC::Open2,
IPC::Open3, and "Bidirectional Communication with Another Pro-
cess" in perlipc for alternatives.)

Subby
07.11.2007, 08:42
Stichwort PIPE schau im INDEX von Programming Perl, habe gerade bei mir geschaut da wird IPC und pipes ab Seite 442 abgehandelt das sollte dir eigentlich eine Vorstellung geben, wie du ein Programm startest und dein STDOUT von diesem als STDIN gelesen wird.

Du kannst dir auch perldoc -f open näher ansehen.

Hi!

Danke für die Info!
Also mit Pipes allein geht es, wie in meinem ersten post geschrieben, ja irgendwie nicht. Er übergibt den Programm meine Eingaben erst wenn ich ein "close" aufrufe. Dann ist das Programm aber wieder geschlossen, was aber nicht passieren darf.

Werde mir die perldoc mal anschauen.

Gruß, Subby

Alamar
07.11.2007, 12:21
Ich nehme mal an dass Buffering Schuld sein wird.
Habe mich jetzt nochmal rangesetzt und selbst mal die Kapitel durchgearbeitet und perldoc gelesen ;)
Dort wird auf 'perldoc perlipc' verwiesen. (Ich hätte mal gleich die Augen aufmachen sollen beim perldoc index)
Naja jedenfalls wird dort genau dein Problem durchgesprochen und mögliche Lösungen mit Beispielcode.
Achja Stichwört damit du es schneller findest ist "Bidirectional" falls du Daten lesen und schreiben willst.

Subby
07.11.2007, 15:39
Hi!

Danke für die Info, das habe ich auch schon gefunden.
Das Problem war, dass dieses Comm.pl Skript von 97 ist und mit Perl5 garnicht läuft.
(Also das Skript das als alternative Angegeben wurde)

Kennst du IPC::Run?
Das habe ich gerade gefunden. So wie ich das bis jetzt lese vielleicht genau das was ich suche. Nur die Verwendung ist für mich irgendwie etwas kryptisch. Hat das vielleicht jemand schonmal verwendet und kann mir da ein paar Tipps geben?

Gruß, Subby

kill4h`
07.11.2007, 17:05
Alamar: Danke für diesen kleinen Einstieg, hab das ja auch im Kamel Buch schon oft gelesen, aber da ichs nie selbst probiert hab, hab ich es auch nie so richtig kapiert. Eine Frage bleibt allerdings noch offen:
Wenn der Child als Leiche keine Ressourcen verbraucht, dann kann er doch egtl. gar nicht laufen, sprich ausgeführt werden, oder?

Subby
07.11.2007, 17:41
Alamar: Danke für diesen kleinen Einstieg, hab das ja auch im Kamel Buch schon oft gelesen, aber da ichs nie selbst probiert hab, hab ich es auch nie so richtig kapiert. Eine Frage bleibt allerdings noch offen:
Wenn der Child als Leiche keine Ressourcen verbraucht, dann kann er doch egtl. gar nicht laufen, sprich ausgeführt werden, oder?

Eine Leiche kann auch nicht laufen. Und ein paar Ressourcen innerhalb des Betriebssystems braucht er natürlich schon noch, sonst würde er ja garnicht existieren. ;)

Alamar
07.11.2007, 18:17
Er läuft auch nicht - ist ja schon beendet. Er hat ja auch State Z und nicht Running oder Sleep etc..
Und die Ressourcen die er braucht sind eben nur der Eintrag in der Prozesstabelle.(+exit informationen etc.)

Mal ein fixes Beispiel konstruiert.

alamar@stronghold tmp $ cat kinder.pl
#!/usr/bin/perl

use warnings;

my $pid = fork();
if($pid == 0) {
exit 1;
}
elsif ($pid > 0) { sleep; }
else { print STDERR "Can't fork...\n"; }



alamar@stronghold tmp $ perl kinder.pl

[1]+ Stopped perl kinder.pl
alamar@stronghold tmp $ bg
[1]+ perl kinder.pl &
alamar@stronghold tmp $ ps -o pid,tty,ppid,size,rss,vsize,pcpu,args
PID TT PPID SZ RSS VSZ %CPU S COMMAND
17502 pts/0 17501 852 2028 5380 0.0 S -bash
17530 pts/0 17502 816 1660 5460 0.0 S perl kinder.pl
17531 pts/0 17530 0 0 0 0.0 Z [perl] <defunct>
17587 pts/0 17502 588 736 4056 0.0 R ps -o pid,tty,ppid,size,rss,vsize


Der hier: 17531 pts/0 17530 0 0 0 0.0 Z [perl] <defunct>
ist im Zombie State und verbraucht auch keine Ressourcen wie man sieht ;)

Für Erläuterungen von Feldern die unklar sind siehe "man ps"

kill4h`
07.11.2007, 19:16
Okay Okay, Prinzip verstanden, danke.