Pipes, Prozesse
-
Also man soll folgenden Shell Befehl mit C simulieren:
"ps -aux | sort -n | head -10 "Mit einer Pipe waer das ja sowas:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> #include <sys/wait.h> int main() { int pid, fd[2], ret; pipe(fd); pid = fork(); if (pid==0) { dup2(fd[1], STDOUT_FILENO); close(fd[0]); close(fd[1]); ret = execlp ("ps", "ps", "-aux", NULL); } else { dup2(fd[0], STDIN_FILENO); close(fd[0]); close(fd[1]); ret=execlp("sort", "sort", "-n", NULL); } return 0; }
Aber wie soll man das mit zwei Pipes hinkriegen??
Ach und die Funktionen popen und system duerfen nicht verwendet werden
-
Du musst halt, statt einfach sort zu starten, noch eine Pipe öffnen, nochmal forken, einen der beiden Prozesse zwischen die Pipes hängen und den anderen ans Ausgabeende der zweiten Pipe, dann sort und head starten.
Das ganze riecht mir zu sehr nach Hausaufgabe, um eine Komplettlösung frei Haus zu liefern. Woran hakt es denn genau?
-
Dieser Thread wurde von Moderator/in SeppJ aus dem Forum C (C89 und C99) in das Forum Linux/Unix verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Also mein Problem ist, dass ich nicht weis wie ich die zwei Pipes hintereinanderschalten soll??
Ich bin jetzt auf sowas gekommen:#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <sys/types.h> #include <sys/wait.h> int main() { int pid, pid2, p1[2], p2[2], ret; pipe(p1); pipe(p2); pid = fork(); pid2 = fork(); if (pid==0) { dup2(p1[1], STDOUT_FILENO); close(p1[0]); close(p1[1]); ret = execlp ("ps", "ps", "-aux", NULL); } else if (pid2 == 0){ dup2(p1[0], STDIN_FILENO); close(p1[0]); close(p1[1]); ret=execlp("sort", "sort", "-n", NULL); } else { dup2(p2[0], STDIN_FILENO); close(p2[0]); close(p2[1]); ret = execlp("head", "head", "-10", NULL); } return 0; }
-
An entsprechender Stelle:
dup2(p1[0], STDIN_FILENO); dup2(p2[1], STDOUT_FILENO); /* <-- */
und du solltest in allen Kindprozessen alle nicht benutzten Pipes schließen. Mindestens im Vaterprozess ist es absolut notwendig, sonst können die Kindprozesse nicht miteinander kommunizieren.
-
ok habs jetzt auf so was gebracht:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> int main() { int pid, pid2, p1[2], p2[2], ret; pipe(p1); pipe(p2); pid = fork(); pid2 = fork(); if (pid==0) { dup2(p1[1], STDOUT_FILENO); close(p1[0]); close(p1[1]); close(p2[0]); close(p2[1]); ret = execlp ("ps", "ps", "-aux", NULL); } else if (pid2 == 0){ dup2(p1[0], STDIN_FILENO); dup2(p2[1], STDOUT_FILENO); close(p2[0]); close(p1[1]); ret=execlp("sort", "sort", "-n", NULL); } else { dup2(p2[0], STDIN_FILENO); close(p1[0]); close(p2[1]); close(p1[1]); ret = execlp("head", "head", "-5", NULL); } return 0; }
Glaub es compiliert richtig und wird auch richtig ausgefuehrt, nur krieg ich seltsame Warnungen??
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.html
Warning: bad ps syntax, perhaps a bogus '-'? See http://procps.sf.net/faq.htmlSignal 17 (CHLD) caught by ps (procps version 3.2.8).
Please send bug reports to feedback@lists.sf.net or albert@users.sf.net
sort: write failed: standard output: Broken pipe
sort: write error
avahi 988 0.0 0.0 3016 1356 ? S 11:20 0:00 avahi-daemon: running [dan-laptop.local]
avahi 988 0.0 0.0 3016 1356 ? S 11:20 0:00 avahi-daemon: running [dan-laptop.local]
avahi 989 0.0 0.0 3016 440 ? S 11:20 0:00 avahi-daemon: chroot helper
avahi 989 0.0 0.0 3016 440 ? S 11:20 0:00 avahi-daemon: chroot helper
daemon 1061 0.0 0.0 2320 356 ? Ss 11:20 0:00 atd
-
Lies den Link doch mal durch:
`Why does schrieb:
According to the POSIX and UNIX standards, the above command asks to display all processes with a TTY (generally the commands users are running) plus all processes owned by a user named "x". If that user doesn't exist, then ps will assume you really meant "ps aux". The warning is given to gently break you of a habit that will cause you trouble if a user named "x" were created.
Ändere
ret = execlp ("ps", "ps", "-aux", NULL);
' einfach zu
ret = execlp ("ps", "ps", "aux", NULL);
'.
-
Gut. Jetzt, wo du ne eigene Lösung hast, so finge ich das an:
#define _GNU_SOURCE #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <stddef.h> #include <stdio.h> #include <stdlib.h> #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) static char *const argv_ps [] = { "ps" , "aux", NULL }; static char *const argv_sort[] = { "sort", "-n" , NULL }; static char *const argv_head[] = { "head", "-20", NULL }; static char *const *const prc_specs[] = { NULL, argv_ps, argv_sort, argv_head }; #define PRC_COUNT (ARRAY_SIZE(prc_specs) - 1) void tie_pipe(int pipe, int stream) { if(pipe != stream) { dup2(pipe, stream); } } void close_pipe(int pipe) { if(pipe != STDIN_FILENO && pipe != STDOUT_FILENO) { close(pipe); } } void collect_children(size_t children_count) { size_t i; for(i = 0; i < children_count; ++i) { wait(NULL); } } int main(void) { pid_t pid[PRC_COUNT + 1]; int pipes[PRC_COUNT + 1][2]; size_t i; char *line = NULL; size_t line_len = 0; pipes[0][0] = STDIN_FILENO; pipes[0][1] = STDOUT_FILENO; for(i = 1; i <= PRC_COUNT; ++i) { pipe(pipes[i]); pid[i] = fork(); if(pid[i] == -1) { fprintf(stderr, "Fehler beim %luten Forken!\n", i); collect_children(i - 1); return -1; } else if(pid[i] == 0) { tie_pipe(pipes[i - 1][0], STDIN_FILENO ); tie_pipe(pipes[i ][1], STDOUT_FILENO); execvp(prc_specs[i][0], prc_specs[i]); } else { close_pipe(pipes[i - 1][0]); close_pipe(pipes[i ][1]); } } tie_pipe(pipes[i - 1][0], STDIN_FILENO); while(getline(&line, &line_len, stdin) != -1) { fputs(line, stdout); } free(line); collect_children(i); return 0; }
Der wesentliche Unterschied ist, dass hier der Hauptprozess für jedes Kommando in der Kanalisation einen eigenen Prozess aufmacht und sie am Ende wieder einsammelt (mit wait), anstatt einen Rattenschwanz vorheriger Prozesse zu spawnen, sich selbst in den letzten zu verwandeln und sich für das Einsammeln auf init zu verlassen. Falls später notwendig, ist eine Kontrolle der Kindprozesse (etwa Abschießen hängender Prozesse) so einfacher zu implementieren, und es ist einfacher erweiterbar.
Allerdings ist dein Ansatz für die Aufgabenstellung völlig ausreichend.