Wie starte ich einen Prozess...
-
Hallo,
ich möchte aus meiner laufenden Anwendung eine andere starten, weiß aber nicht wie ich das anfangen soll.
Unter Windows würde ich "CreateProcess" und dann ein Programm laufen lassen, aber unter Linux....
Gruß
Franky
-
Stichworte:
fork
undexec
.Bei dem Rest sollte dir eine Suchmaschine helfen können.
-
Hi,
ja, hatte mir auch fork, exec, system,.. angesehen. Ich weiß nicht ob ich richtig liege, aber bei meiner Anwendung handelt es sich um einen Client, der andere Anwendungen starten soll.
Wenn ich fork nutze, das wird doch von meinem Client eine Kopie gemacht, der meldet sich dann wieder am Server an... während der ursprüngliche Prozess (Client) dann hinter fork weiter macht (fork dupliziert meinen Prozess). Das gibt Probleme mit dem Server, der sich den Namen des Clients merkt und somit festellt daß zwei Client's gleichen Names sich verbinden wollen, oder liege ich da falsch?mein bisheriger Code...
switch(fork){ case -1: cout << "Creation failed" << endl; //exit(-1); break; case 0: execl("./processA", "./processA", "arg", "arg", 0); //exit(-1); break; default: int status; if (wait(&status) < 0) { cout << "Fehler bein warten auf Kindprozess" << endl; }
Kein "processA" weit und breit....
da ich mich derzeit nicht am Linux-Arbeitsplatzrechner befinde kann ich folgenden Code nicht testen...
Equivalent Linux code #include <stdlib.h> #include <stdio.h> int processId; char *exec_path_name; char * cmd_line ; cmd_line = (char *) malloc(strlen(_cmd_line ) + 1 ); if(cmd_line == NULL) return RC_NOT_ENOUGH_MEMORY; strcpy(cmd_line, _cmd_line); if( ( *processId = fork() ) == 0 ) // Create child { char *pArg, *pPtr; char *argv[WR_MAX_ARG + 1]; int argc; if( ( pArg = strrchr( exec_path_name, '/' ) ) != NULL ) pArg++; else pArg = exec_path_name; argv[0] = pArg; argc = 1; if( cmd_line != NULL && *cmd_line != '\0' ) { pArg = strtok_r(cmd_line, " ", &pPtr); while( pArg != NULL ) { argv[argc] = pArg; argc++; if( argc >= WR_MAX_ARG ) break; pArg = strtok_r(NULL, " ", &pPtr); } } argv[argc] = NULL; execv(exec_path_name, argv); free(cmd_line); exit( -1 ); } else if( *processId == -1 ) { *processId = 0; free(cmd_line); return RC_PROCESS_NOT_CREATED; }
Aber ich weiß nicht ob der mein Problem lößt.
Unter Linux kann ich ja nicht wie unter Windows einfach mal so einen Prozess erzeugen....
Oder, da fällt mir ein, kann ich ein Skript ausführen, das meinen Prozess erzeugt und wenn ja wie?
Gruß
Franky
-
FrankTheFox schrieb:
Wenn ich fork nutze, das wird doch von meinem Client eine Kopie gemacht
Ja. Soweit richtig.
FrankTheFox schrieb:
, der meldet sich dann wieder am Server an...
Nein. Deine Kopie meldet sich nirgendwo an. Du kannst die beiden Prozesse nur am Rückgabe wert von
fork
unterscheiden.Wenn dein Prozess eine Netzwerk-Verbindung offen hat. Dann teilen sich beide Prozesse die gleiche Verbindung. Es wird keine neue aufgebaut.
Beantwortet das deine Frage soweit?
FrankTheFox schrieb:
da ich mich derzeit nicht am Linux-Arbeitsplatzrechner befinde kann ich folgenden Code nicht testen...
Das ließe sich ja nun leicht ändern. Und wenn du deine Betriebssystem-Installation nicht gefährden willst, kannst du ja mal einen Blick auf Virtual Box werfen.
FrankTheFox schrieb:
Oder, da fällt mir ein, kann ich ein Skript ausführen, das meinen Prozess erzeugt und wenn ja wie?
Um ein Skript zu starten, musst du auch einen Prozess starten...
-
ProgChild schrieb:
Wenn dein Prozess eine Netzwerk-Verbindung offen hat. Dann teilen sich beide Prozesse die gleiche Verbindung. Es wird keine neue aufgebaut.
Dann ist Linux definitiv völlig anders als Windows. Das mit der Identischen Kopie verwirrt mich etwas, weil ich befürchte das ich dann Nachrichten doppelt schcke, da ich dann ja zwei identische Clients besitze die laufen.
ProgChild schrieb:
Das ließe sich ja nun leicht ändern. Und wenn du deine Betriebssystem-Installation nicht gefährden willst, kannst du ja mal einen Blick auf Virtual Box werfen.
Nein, ich komme definitiv auf den Arbeitsplatzrechner von aussen nicht ran.
Die exec(l, lp, le, v, vp) Funktionen sind auch so ein Knaller, die erzetzen gleich den Code im Speicher, wow.
Wass ist den mit Datei ausühren gemeint....?
Gruß
Franky
-
FrankTheFox schrieb:
Dann ist Linux definitiv völlig anders als Windows. Das mit der Identischen Kopie verwirrt mich etwas, weil ich befürchte das ich dann Nachrichten doppelt schcke, da ich dann ja zwei identische Clients besitze die laufen.
Dafür gibt es ja den Rückgabe-Wert von
fork
. Du richtest dann eine Weiche ein. Der eine Code macht das, was der Client eben tun soll und der andere führtexec
aus und ersetzt sich selbst so durch den neuen Prozess. Da wird nichts doppelt geschickt.FrankTheFox schrieb:
Nein, ich komme definitiv auf den Arbeitsplatzrechner von aussen nicht ran.
Aber du kannst dir ein Linux-System aufsetzen und damit mal ein bisschen mit fork rum hantieren.
FrankTheFox schrieb:
Die exec(l, lp, le, v, vp) Funktionen sind auch so ein Knaller, die erzetzen gleich den Code im Speicher, wow.
Macht auch nur Sinn in Kombination mit
fork
.FrankTheFox schrieb:
Wass ist den mit Datei ausühren gemeint....?
?
Aber warum fragst du nicht mal Google? Google: tutorial fork exec
Da findest du z.B.: http://www.ibm.com/developerworks/aix/library/au-unixprocess.html
-
FrankTheFox schrieb:
mein bisheriger Code...
switch(fork){ case -1: cout << "Creation failed" << endl; //exit(-1); break; case 0: execl("./processA", "./processA", "arg", "arg", 0); //exit(-1); break; default: int status; if (wait(&status) < 0) { cout << "Fehler bein warten auf Kindprozess" << endl; }
Kein "processA" weit und breit....
Kein Wunder, da fehlen zwei Klammern hinter dem
fork
. ;3
-
Hi,
ich beginne jetzt in der main so....
int main() { int processId; processId = fork(); cout << "forked to : " << processId << endl; if( processId == 0 ) // Create child { execl("/bin/bash","/bin/bash",(char *)0); // Shell starten } else if( processId == -1) { perror("fork"); } else{ // Parent init_server_connection(); get_client_related_messages(&msgs); ... return 0; } }
mit ps xfg
sehe ich:
\_ konsole [.. | \_ /bin/bash | \_ ./myApp | \_ /bin/bash
Aber ich sehe doch keine Bash
Im Terminal sehe nach Client relevanten Ausgaben
[1]+ Stopped ./myApp
und dann die Eigabeauforderung! MyApp laüft noch....Gruß
Franky
-
Sobald der Eltern-Pozess beendet wird, werden auch dessen Standard Ein- und Ausgabe-Dateideskriptoren geschlossen. Und da dank
fork
Eltern- und Kind-Prozess diese gemeinsam nutzen, verwandelt sich der Kind-Prozess in einen Daemon ohne Standard Ein- und Ausgabe. :3 Daher siehst du nichts von der bash. ;3 Wenn du möchtest, dass die bash nach dem Beenden des Eltern-Prozesses noch benutzbar bleibt, kannst du den Spieß umdrehen:#include <cstdio> #include <unistd.h> int main() { int processId = fork(); if(!processId) { // do your stuff here yiff(); return 0; } else if(processId == -1) { perror("fork"); return 1; } else { execl("/bin/bash", "/bin/bash", NULL); } }
Jetzt ist der Eltern-Prozess
/bin/bash
und der Kind-Prozess dein Netzwerk-Dingens. ^^
-
Hi,
danke, aber ich glaube das Problem liegt woanders....
int aa = execl("/usr/home/myUsrName/Workpace/myApp", "myApp" ,(char *)0); // App starten cout << "aa: " << aa << endl;
pwd im Ordner "myApp" ergibt:
/home/myUsrName/Workspace/myApp
Ich sehe das beim Lauf:
aa: -1
Gruß
Franky
-
FrankTheFox schrieb:
int aa = execl("/usr/home/myUsrName/Workpace/myApp", "myApp" ,(char *)0); // App starten cout << "aa: " << aa << endl;
pwd im Ordner "myApp" ergibt:
/home/myUsrName/Workspace/myApp
Warum ist da dann ein
/usr
vor dem Pfad? :3 Und eins
fehlt inWorkpace
. ^^Abgesehen davon: Wenn
/home/myUsrName/Workspace/myApp
der Ordner ist, in dem dein Programm liegt, dann musst du den Programmnamen noch mit dran hängen. Und der gesamte Pfad muss auch im zweiten Argument stehen. Beim/bin/bash
-Beispiel hast du das noch richtig gemacht. ;3int aa = execl("/home/myUsrName/Workspace/myApp/myApp", "/home/myUsrName/Workspace/myApp/myApp", (char *)0); // App starten cout << "aa: " << aa << endl;
FrankTheFox schrieb:
Ich sehe das beim Lauf:
aa: -1
perror("execl");
sagt dir, wo genau das Problem ist. :3
-
Hi,
ich habe im Internet folgenden Code gefunden....
#define READ_END(x) x[0] #define WRITE_END(x) x[1] int run_program (const char* progname, char* const args[], char* const env[]) { int pipefd_stdin[2]; int pipefd_stdout[2]; int pipefd_stderr[2]; if (pipe(pipefd_stdin) == -1) { perror("pipe"); } if (pipe(pipefd_stdout) == -1) { perror("pipe"); } if (pipe(pipefd_stderr) == -1) { perror("pipe"); } int subproc = fork (); printf("forked to pid %d\n", subproc); if (subproc == -1) { perror("fork"); } else if (subproc == 0) { close(WRITE_END(pipefd_stdin)); close(READ_END(pipefd_stdout)); close(READ_END(pipefd_stderr)); dup2(READ_END(pipefd_stdin), STDIN_FILENO); dup2(WRITE_END(pipefd_stdout), STDOUT_FILENO); dup2(WRITE_END(pipefd_stderr), STDERR_FILENO); execve(progname, args, env); } else { close(READ_END(pipefd_stdin)); close(WRITE_END(pipefd_stdout)); close(WRITE_END(pipefd_stderr)); int i; char buff[256]; char buff2[257]; while ((i = read(READ_END(pipefd_stdout), &buff, sizeof(buff))) != 0) { if (i == -1) { perror("read"); } bzero(&buff2, sizeof(buff2)); memcpy (&buff2, &buff, i); printf("%s...", &buff2); fflush(0); } } }
wenn ich jetzt nur das Programm aufrufe, also meinen eigentlichen Elterncode rauslasse...
int main(){ const char* progname = "/home/myUsrName/Workspace/myApp/myApp" void* nullobj = NULL; char** args = (char**) &nullobj; printf("running...\n"); run_program (progname, args, args); while(1){ ... //warte bis taste... } }
dann klappts (zumindest der Start des Programms). Aber warum?
Gruß
Franky
-
Hier wir über eine pipe die Ausgabe den Kind-Prozesses an den Eltern-Prozess weitergeleitet, der diese dann schließlich über die Standard-Ausgabe ausgibt. ^^"
Wie gesagt, wenn du möchtest, dass dein Kind Prozess benutzbar bleibt, starte ihn im Eltern-Prozess und tu dein Netzwerk Zeugs im Kind-Prozess, wie ich es auf der vorherigen Seite beschreiben habe. Das ist wesentlich einfacher. ;3
-
Hallo,
ich habe jetzt das so gemacht.... (Wobei ich das mit den Pipes gar nicht so schlecht finde, mich aber frage ob ich das brauche denn die Ausgaben der "Childs" sehe ich ja so auch).
int main() { int pid = fork(); if( pid == 0 ){ //child1!!!!!!! cout << "start myApp1................ " << endl; int aa = execl("/home/myUsrName/Workspace/myApp1/myApp1, "/home/myUsrName/Workspace/myApp1/myApp1", (char *)0); // App starten cout << "(Fehler) myApp1: " << aa << endl; perror("execl"); return (-1); } pid = fork(); if( pid == 0 ){ //child!!!!!!! cout << "start myApp2................ " << endl; int aa = execl("/home/myUsrName/Workspace/myApp2/myApp2, "/home/myUsrName/Workspace/myApp2/myApp2, (char *)0); // App starten cout << "(Fehler) myApp2 " << aa << endl; perror("execl"); return (-1); } //Ab hier dann der parent //init_server_stuff(); while(1){ //code stuff } //close_server_stuff(); return 0; }
Im Elternprozess geht die Ausführung nach fork weiter und execl kehrt nicht zurück (ausser wenn ein Fehler auftritt)
dann macht das Child eine Serververbindung auf während der Elternprozess das nächste "Kind" startet und das macht eine Serververbindung auf. Dann schließlich der Parent der eine Serververbindung aufmacht...beide Anwendungen werden gestartet.... und laufen...
und ich sehe die Ausgaben im Terminal...
Ich brauche noch nicht einmal den child im Elternprozess starten...Wie kann ich den jetzt den z.B. myApp2 stoppen und wieder starten und wie kriege ich mit ob der Prozess auch wirklich gestoppt hat.
Gruß
Franky
-
FrankTheFox schrieb:
Wie kann ich den jetzt den z.B. myApp2 stoppen und wieder starten und wie kriege ich mit ob der Prozess auch wirklich gestoppt hat.
Das geht mit man: kill(2) und man: waitpid(2).
Welche Signale du mit
kill
senden kannst, steht hier: man: signal(7).
-
Hallo,
danke. ich habe jetzt ein wenig rumgespielt um zu verstehen wie genau fork und exec* funktionert. Das mit den Pipes lässt mir auch keine Ruhe...also
habe jetzt erstmal#define MAX 257 #define MAX_PIPE_FD 2 typedef struct { int pipefd_stdin[ MAX_PIPE_FD ]; int pipefd_stdout[ MAX_PIPE_FD ]; int pipefd_stderr[ MAX_PIPE_FD ]; } pipe_type; int run_executable ( pipe_type &child_pipe, const char* progname, int &child_pid ); int read_pipebuffer( char* buff, int pipe_fd );
und dann...
int read_pipebuffer( char* buff, int pipe_fd ) { char tmpBuff[ MAX -1 ]; int i; while( ( i = read( pipe_fd, &tmpBuff, sizeof( tmpBuff ) ) ) != 0 ){ if( i == -1 ){ perror( "read" ); return 0; } bzero( buff, MAX ); memcpy( buff, &tmpBuff, i ); fflush( 0 ); } return 1; }
und...
int run_executable( pipe_type &child_pipe, const char* progname, int &child_pid ) { if( pipe( child_pipe.pipefd_stdin ) == -1 ){ perror("pipe"); } if( pipe( child_pipe.pipefd_stdout ) == -1 ){ perror("pipe"); } if( pipe( child_pipe.pipefd_stderr ) == -1 ){ perror("pipe"); } int pid = fork(); child_pid = pid; if (pid == -1){ perror("fork"); } else if( pid == 0 ){ //code executed by Child //close write end of standard in close( child_pipe.pipefd_stdin[1] ); //close read end of standard out close( child_pipe.pipefd_stdout[0] ); //close read end of standard err close( child_pipe.pipefd_stderr[0] ); //to make read end of pipe-to-child into standard input. dup2( child_pipe.pipefd_stdin[0], STDIN_FILENO ); //to make write end of pipe-to-child into standard out. dup2( child_pipe.pipefd_stdout[1], STDOUT_FILENO ); //to make write end of pipe-to-child into standard error. dup2( child_pipe.pipefd_stderr[1], STDERR_FILENO ); //run executable execl( progname, progname, (char *)0 ); } else{ close( child_pipe.pipefd_stdin[0] ); //read end close( child_pipe.pipefd_stdout[1] ); //write end close( child_pipe.pipefd_stderr[1] ); //write end } return 0; }
Ich habe mir eine App gebaut, die nur die Tools startet (ohne Serververbindung selber zu öffnen...)
int main() { const char* app1_name = "/home/myUsrName/Workspace/myApp1/myApp1"; const char* app2_name = "/home/myUsrName/Workspace/myApp2/myApp2"; const char* app3_name = "/home/myUsrName/Workspace/myApp3/myApp3"; pipe_type app1_pipe; int app1_pid; pipe_type app2_pipe; int app2_pid; pipe_type app3_pipe; int app3_pid; char buff[ MAX ]; while(1){ cout << "..........................." << endl; //first start app1 (only once)... if ( waitpid( app1_pid, NULL, WNOHANG ) == -1 ){ cout << "kein prozess!!!!!!!!!!!!!!!!!" << endl; run_executable ( app1_pipe, app1_name, app1_pid); } read_pipebuffer( buff, app1_pipe.pipefd_stdout[0] ); cout << ";;;;;;;;;;;;;;;;;;;;;;" << endl; //printf("%s\n\n", buff); } }
nur sehe ich nicht ";;;;;;;;;;;;;;;;;;;;;;" obwohl app1 was in die Ausgabe schreibt.
Was habe ich falsch gemacht?
Gruß
-
Hi,
habe jetzt geschafft App1 zu starten, aber nicht App2....
//User includes #include "AccServer.h" //system includes #include <iostream> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #include <sys/wait.h> #include <string.h> using namespace std; int App1_pid = 0; int App2_pid = 0; const char* App1path = "/home/frank/workspace/App1/App1"; const char* App2path = "/home/frank/workspace/App1/App2"; pipe_type App1_Pipe; pipe_type App2_Pipe; int run_executable( pipe_type &child_pipe, const char* progname, int &child_pid ) { if( pipe( child_pipe.pipe_stdin.pipe_fd ) == -1) { perror( "pipe" ); } //init stdin stream PIPE_READ_END( child_pipe.pipe_stdin.fnctl_flags ) = fcntl( PIPE_READ_END( child_pipe.pipe_stdin.pipe_fd ), F_GETFL ); fcntl( PIPE_READ_END( child_pipe.pipe_stdin.fnctl_flags ), F_SETFL, PIPE_READ_END( child_pipe.pipe_stdin.fnctl_flags ) | O_NONBLOCK ); if( pipe( child_pipe.pipe_stdout.pipe_fd ) == -1) { perror( "pipe" ); } //init stdout stream PIPE_READ_END( child_pipe.pipe_stdout.fnctl_flags ) = fcntl( PIPE_READ_END( child_pipe.pipe_stdout.pipe_fd ), F_GETFL ); fcntl( PIPE_READ_END( child_pipe.pipe_stdout.fnctl_flags ), F_SETFL, PIPE_READ_END( child_pipe.pipe_stdout.fnctl_flags ) | O_NONBLOCK ); if( pipe( child_pipe.pipe_stderr.pipe_fd ) == -1) { perror( "pipe" ); } //init stderr stream PIPE_READ_END( child_pipe.pipe_stderr.fnctl_flags ) = fcntl( PIPE_READ_END( child_pipe.pipe_stderr.pipe_fd ), F_GETFL ); fcntl( PIPE_READ_END( child_pipe.pipe_stderr.fnctl_flags ), F_SETFL, PIPE_READ_END( child_pipe.pipe_stderr.fnctl_flags ) | O_NONBLOCK ); int pid = vfork(); if( pid == -1 ) { perror("fork"); exit( EXIT_FAILURE ); } else if(pid == 0){ close( PIPE_WRITE_END( child_pipe.pipe_stdin.pipe_fd ) ); close( PIPE_READ_END( child_pipe.pipe_stdout.pipe_fd ) ); close( PIPE_READ_END( child_pipe.pipe_stderr.pipe_fd ) ); dup2( PIPE_READ_END( child_pipe.pipe_stdin.pipe_fd ), STDIN_FILENO ); dup2( PIPE_WRITE_END( child_pipe.pipe_stdout.pipe_fd ), STDOUT_FILENO ); dup2( PIPE_WRITE_END( child_pipe.pipe_stderr.pipe_fd ), STDERR_FILENO ); execl( progname, progname, (char*) 0 ); } else if( pid > 0 ){ child_pid = pid; close( PIPE_READ_END( child_pipe.pipe_stdin.pipe_fd ) ); close( PIPE_WRITE_END( child_pipe.pipe_stdout.pipe_fd ) ); close( PIPE_WRITE_END( child_pipe.pipe_stderr.pipe_fd ) ); } return 0; } int read_pipebuffer( char* buff, int &no_bytes, int pipe_fd ) { char tmpBuff[ MAX_BUFFER ] = {0}; int i; size_t bytesread = 0; fd_set fds; struct timeval tv = {0}; FD_SET( pipe_fd, &fds); int rv = select( pipe_fd + 1, &fds, NULL, NULL, &tv ); if( rv == -1 ) perror("select"); else if ( rv > 0 ){ if( FD_ISSET( pipe_fd, &fds ) ) { bytesread = read( pipe_fd, tmpBuff, sizeof( tmpBuff ) ); no_bytes = bytesread; if( bytesread == 0 ) { //printf(" App closed!\n"); return -1; } } } if(bytesread > 0 ){ if( strlen( tmpBuff ) > 0 ){ sprintf( buff, "%s", tmpBuff ); tmpBuff[ MAX_BUFFER ] = 0; } } FD_CLR( pipe_fd, &fds ); return 0; } int main() { char buff[ MAX_BUFFER ]; cout << "Ok, jetzt gehts los." << endl; while (1) { if( waitpid( App1_pid, NULL, WNOHANG ) == -1 ) { run_executable( App1_Pipe, App1path, App1_pid ); } int no_bytes = 0; read_pipebuffer( buff, no_bytes, PIPE_READ_END(App1_Pipe.pipe_stdout.pipe_fd) ); if( no_bytes > 0 ){ char *pWord = NULL; pWord = strstr( buff, "Hello"); if(pWord){ printf("Hello found!"); if( waitpid( App2_pid, NULL, WNOHANG ) == -1 ) { printf("vor run_exec... App2!"); run_executable( App2_Pipe, App2path, App2_pid ); } } pWord = NULL; pWord = strstr( buff, "kill App1"); if( pWord ){ kill( App1_pid, SIGKILL ); printf("App1 terminated!"); } pWord = NULL; printf("%s\n", buff); } } return 0; } //Konsole mit ps axfg zeigt Prozesse!!!!
#define PIPE_READ_END(x) x[0] #define PIPE_WRITE_END(x) x[1] typedef enum{ acc_read = 0, acc_write = 1 } pipe_access_type; #ifndef ACCSERVER_H_ #define ACCSERVER_H_ #define MAX_PIPE_FD 2 #define MAX_BUFFER 257 /* * standard streams are preconnected input and output channels * between a computer program and its environment (typically a * text terminal) when it begins execution. */ typedef struct { int pipe_fd[ MAX_PIPE_FD ]; int fnctl_flags [ MAX_PIPE_FD ]; pipe_access_type pipe_access; } pipe_stdin_type, pipe_stdout_type, pipe_stderr_type; typedef struct{ pipe_stderr_type pipe_stderr; pipe_stdin_type pipe_stdin; pipe_stdout_type pipe_stdout; } pipe_type; int run_executable( pipe_type &child_pipe, const char* progname, int &child_pid ); int read_pipebuffer( char* buff, int &no_bytes, int pipe_fd ); #endif /* ACCSERVER_H_ */
Gruß
Franky