2009-02-13 16 views

Antwort

24

Verwenden Sie nicht popen(), und schreiben Sie Ihren eigenen Wrapper, der das tut, was Sie möchten.

Es ist relativ einfach zu fork(), und ersetzen Sie dann stdin & stdout mit dup2(), und rufen Sie dann exec() auf Ihr Kind.

Auf diese Weise haben Ihre Eltern die genaue Kind-PID und Sie können kill() verwenden.

Google Suche nach "popen2() Implementierung" für einige Beispielcode auf wie zu implementieren, was popen() tut. Es ist nur ein Dutzend oder so Linien lang. Entnommen dzone.com können wir ein Beispiel sehen, die wie folgt aussieht:

#define READ 0 
#define WRITE 1 

pid_t 
popen2(const char *command, int *infp, int *outfp) 
{ 
    int p_stdin[2], p_stdout[2]; 
    pid_t pid; 

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) 
     return -1; 

    pid = fork(); 

    if (pid < 0) 
     return pid; 
    else if (pid == 0) 
    { 
     close(p_stdin[WRITE]); 
     dup2(p_stdin[READ], READ); 
     close(p_stdout[READ]); 
     dup2(p_stdout[WRITE], WRITE); 

     execl("/bin/sh", "sh", "-c", command, NULL); 
     perror("execl"); 
     exit(1); 
    } 

    if (infp == NULL) 
     close(p_stdin[WRITE]); 
    else 
     *infp = p_stdin[WRITE]; 

    if (outfp == NULL) 
     close(p_stdout[READ]); 
    else 
     *outfp = p_stdout[READ]; 

    return pid; 
} 

NB: Scheint, wie popen2() ist das, was Sie wollen, aber meine Verteilung scheint nicht mit dieser Methode zu kommen. Eigentlich

+0

Dies löst nicht das Problem der Speicherduplizierung von fork. es ist möglich, dass wir aus diesem Grund keinen Anruf ausrufen wollen – Will

+0

@phooji Was hat Python mit irgendetwas zu tun? –

+0

@ MahmoudAl-Qudsi: Whoops. Ich muss mich über zu viele Python-Fragen gekümmert haben. [Früherer Python-bezogener Kommentar redigiert] – phooji

0

Der offensichtliche Weg ist System ("pkill process_name");

Dies ist eindeutig problematisch, wenn mehr als eine Instanz des Prozesses ausgeführt wird.

+0

Dies ist der Fall, wenn mehrere Instanzen ausgeführt werden und eine präzise Instanz ausgewählt werden muss. – jldupont

4

popen startet eigentlich keinen Thread, sondern verzweigt einen Prozess. Wenn ich mir die Definition ansehe, sieht es nicht so aus, als gäbe es einen einfachen Weg, die PID dieses Prozesses zu bekommen und sie zu töten. Es könnte schwierig sein, den Prozessbaum zu untersuchen, aber ich denke, dass Sie besser mit den Funktionen pipe, fork und exec arbeiten sollten, um das Verhalten von popen nachzuahmen. Dann können Sie PID verwenden, das Sie von fork() erhalten, um den Kindprozess zu beenden.

3

, wenn der Prozess tut I/O (was es sein sollte, warum sonst popen statt system (3)?), Dann sollte pclose Whack es mit einem SIGPIPE das nächste Mal versucht, zu lesen oder zu schreiben, und es sollte schön überstürzen :-)

5

Hier ist eine verbesserte Version von popen2 (Kredit ist fällig für Sergey L.). Die von Slacy veröffentlichte Version gibt nicht die PID des in popen2 erstellten Prozesses zurück, sondern die PID, die sh zugewiesen ist.

pid_t popen2(const char **command, int *infp, int *outfp) 
{ 
    int p_stdin[2], p_stdout[2]; 
    pid_t pid; 

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) 
     return -1; 

    pid = fork(); 

    if (pid < 0) 
     return pid; 
    else if (pid == 0) 
    { 
     close(p_stdin[WRITE]); 
     dup2(p_stdin[READ], READ); 
     close(p_stdout[READ]); 
     dup2(p_stdout[WRITE], WRITE); 

     execvp(*command, command); 
     perror("execvp"); 
     exit(1); 
    } 

    if (infp == NULL) 
     close(p_stdin[WRITE]); 
    else 
     *infp = p_stdin[WRITE]; 

    if (outfp == NULL) 
     close(p_stdout[READ]); 
    else 
     *outfp = p_stdout[READ]; 

    return pid; 
} 

Die neue Version ist, ich habe Idee @slacy folgen mit

char *command[] = {"program", "arg1", "arg2", ..., NULL}; 
+0

Ich sah keinen Unterschied in pid Teil; Kannst du Kommentare zum Unterschied Teil aktualisieren. – nayab

+0

Danke Schach für deine Version, wirklich gut! –

0

genannt werden, die Funktion popen2 erstellen.
Aber Problem gefunden, wenn Child-Prozess stirbt, Elternprozess, der noch lesen Dateideskriptor outfp nicht von der Funktion zurückkehren.

Das könnte durch Hinzufügen schließen unuse pipe auf Elternprozess beheben.

close(p_stdin[READ]); 
close(p_stdout[WRITE]); 

Wir können richtig pid neuen Prozess erhalten, indem bash als Shell verwenden.

execl("/bin/bash", "bash", "-c", command, NULL); 

Wenn Kind-Prozess des Aufrufer Funktion popen2 soll Status des Kindprozesses durch Anruf sammeln pclose2 sterben. Wenn wir diesen Status nicht sammeln, kann der Prozess ein Zombie-Prozess sein, wenn er endet.

Dies ist der vollständige Code, der getestet und wie erwartet funktioniert.

#define READ 0 
#define WRITE 1 

pid_t 
popen2(const char *command, int *infp, int *outfp) 
{ 
    int p_stdin[2], p_stdout[2]; 
    pid_t pid; 

    if (pipe(p_stdin) != 0 || pipe(p_stdout) != 0) 
     return -1; 

    pid = fork(); 

    if (pid < 0) 
     return pid; 
    else if (pid == 0) 
    { 
     dup2(p_stdin[READ], STDIN_FILENO); 
     dup2(p_stdout[WRITE], STDOUT_FILENO); 

    //close unuse descriptors on child process. 
    close(p_stdin[READ]); 
    close(p_stdin[WRITE]); 
    close(p_stdout[READ]); 
    close(p_stdout[WRITE]); 

     //can change to any exec* function family. 
     execl("/bin/bash", "bash", "-c", command, NULL); 
     perror("execl"); 
     exit(1); 
    } 

    // close unused descriptors on parent process. 
    close(p_stdin[READ]); 
    close(p_stdout[WRITE]); 

    if (infp == NULL) 
     close(p_stdin[WRITE]); 
    else 
     *infp = p_stdin[WRITE]; 

    if (outfp == NULL) 
     close(p_stdout[READ]); 
    else 
     *outfp = p_stdout[READ]; 

    return pid; 
} 

int 
pclose2(pid_t pid) { 
    int internal_stat; 
    waitpid(pid, &internal_stat, 0); 
    return WEXITSTATUS(internal_stat); 
} 
0

ich einfach in der (bash) Skript setzen, in der ersten Zeile:

echo PID $$ 

dann las ich die pid, und es verwenden, eine tun: kill (pid, 9)

+0

popen ist käsig, um damit zu beginnen, das ist eine nette käsige Lösung des käsigen Problems. – stu

Verwandte Themen