Durchführung mehrerer Rohre in C
Ich versuche zu implementieren mehrere Rohre in meiner shell in C. fand ich ein tutorial auf dieser website und die Funktion, die ich gemacht habe, basiert auf diesem Beispiel. Hier ist die Funktion
void executePipes(cmdLine* command, char* userInput) {
int numPipes = 2 * countPipes(userInput);
int status;
int i = 0, j = 0;
int pipefds[numPipes];
for(i = 0; i < (numPipes); i += 2)
pipe(pipefds + i);
while(command != NULL) {
if(fork() == 0){
if(j != 0){
dup2(pipefds[j - 2], 0);
}
if(command->next != NULL){
dup2(pipefds[j + 1], 1);
}
for(i = 0; i < (numPipes); i++){
close(pipefds[i]);
}
if( execvp(*command->arguments, command->arguments) < 0 ){
perror(*command->arguments);
exit(EXIT_FAILURE);
}
}
else{
if(command != NULL)
command = command->next;
j += 2;
for(i = 0; i < (numPipes ); i++){
close(pipefds[i]);
}
while(waitpid(0,0,0) < 0);
}
}
}
Nachdem Sie es ausgeführt haben und Sie einen Befehl eingeben, wie zum Beispiel ls | grep bin
die shell hängt nur dort und nicht ausgeben, ohne Ergebnis. Ich stellte sicher, ich Schloss alle Rohre. Aber es hängt ja nur. Ich dachte, dass es die waitpid
das war das problem. Ich entfernte die waitpid
und nach der Ausführung bekomme ich keine Ergebnisse. Was habe ich falsch gemacht? Danke.
Code Hinzugefügt:
void runPipedCommands(cmdLine* command, char* userInput) {
int numPipes = countPipes(userInput);
int status;
int i = 0, j = 0;
pid_t pid;
int pipefds[2*numPipes];
for(i = 0; i < 2*(numPipes); i++){
if(pipe(pipefds + i*2) < 0) {
perror("pipe");
exit(EXIT_FAILURE);
}
}
while(command) {
pid = fork();
if(pid == 0) {
//if not first command
if(j != 0){
if(dup2(pipefds[(j-1) * 2], 0) < 0){
perror(" dup2");///j-2 0 j+1 1
exit(EXIT_FAILURE);
//printf("j != 0 dup(pipefd[%d], 0])\n", j-2);
}
//if not last command
if(command->next){
if(dup2(pipefds[j * 2 + 1], 1) < 0){
perror("dup2");
exit(EXIT_FAILURE);
}
}
for(i = 0; i < 2*numPipes; i++){
close(pipefds[i]);
}
if( execvp(*command->arguments, command->arguments) < 0 ){
perror(*command->arguments);
exit(EXIT_FAILURE);
}
} else if(pid < 0){
perror("error");
exit(EXIT_FAILURE);
}
command = command->next;
j++;
}
for(i = 0; i < 2 * numPipes; i++){
close(pipefds[i]);
puts("closed pipe in parent");
}
while(waitpid(0,0,0) <= 0);
}
}
Stilistischer Hinweis für Beiträge: entfernen Sie den auskommentierten code, und entfernen Sie überflüssige Leerzeichen.
Getan
können Sie nach dem vollständigen code der Implementierung, wie, warum Sie brauchte, um struct-Befehle
Getan
können Sie nach dem vollständigen code der Implementierung, wie, warum Sie brauchte, um struct-Befehle
InformationsquelleAutor mkab | 2011-12-05
Du musst angemeldet sein, um einen Kommentar abzugeben.
Ich glaube, das Problem hier ist, dass Ihr wartet und schließen innerhalb der gleichen Schleife, die die Kinder zu erschaffen. Auf der ersten iteration, das Kind exec ("zerstört die Kind-Programm, überschreiben Sie es mit Ihrem ersten Befehl) und dann den Eltern schließt alle seine Dateideskriptoren und wartet, bis das Kind fertig ist, bevor es durchläuft auf der Erstellung des nächsten Kindes. An diesem Punkt, da die Muttergesellschaft geschlossen hat, alle seine Rohre, keine weiteren Kinder haben nichts zu schreiben oder Lesen. Da Sie nicht die überprüfung für den Erfolg Ihrer dup2 ruft, dieses ist gehen un-bemerkt.
Wenn Sie möchten, um die gleiche Schleife, die Sie benötigen um sicherzustellen, dass die Eltern nur schließt die Dateideskriptoren, die bereits verwendet wurden, lässt aber jene, die noch nicht allein. Dann, nachdem alle Kinder geschaffen worden, und Ihre Eltern warten können.
BEARBEITEN: ich mischte die Eltern/Kind in meiner Antwort, aber die Argumentation immer noch gilt: der Prozess, dass sich an der Gabel wieder schließt alle Kopien der Rohre, so dass jeder Prozess nach der ersten Gabel keine gültige Datei-Deskriptoren zu Lesen/schreiben.
pseudo-code, mit einem array von Leitungen erstellt-front:
In diesem code, den ursprünglichen übergeordneten Prozess erstellt ein Kind für jeden Befehl und deshalb überlebt die ganze Angelegenheit. Die Kinder prüfen, um zu sehen, wenn Sie sollten Sie bekommen Ihren input von den vorherigen Befehl, und wenn Sie senden Ihre Ausgabe an den nächsten Befehl. Dann schließen Sie alle Ihre Kopien der pipe-Datei-Deskriptoren und dann exec. Die Eltern nicht alles tun, aber Gabel, bis es ein Kind wird für jeden Befehl. Es schließt sich dann alle Kopien der Deskriptoren und kann gehen, um zu warten.
Erstellen alle Rohre, die Sie zuerst benötigen, und verwalten Sie Sie in der Schleife, ist schwierig und erfordert einige array-Arithmetik. Ziel ist es aber, sieht wie folgt aus:
Erkennen, dass zu einem bestimmten Zeitpunkt, müssen Sie nur zwei Sätze von Rohren (die Rohre zu den vorherigen Befehl, und das Rohr, um den nächsten Befehl) vereinfachen Sie Ihren code und machen es ein wenig robuster. Ephemient gibt den pseudo-code für diese hier. Sein code ist sauberer, weil die Eltern und Kind nicht zu tun haben, unnötige Schleifen in der Nähe der UNO-benötigte Datei-Deskriptoren, denn die Eltern können einfach schließen Sie Ihr Kopien der Datei-Deskriptoren, die sofort nach der Gabel.
Als kleiner Hinweis: Sie sollten immer prüfen die Rückgabewerte der pipe, dup2, fork und exec.
EDIT 2: Tippfehler in pseudo-code. OP: num-Rohre würde die Zahl der Rohre. E. g., "ls | grep foo | sort-r" müsste 2 Rohre.
Vielen Dank für den pseudo-code. In deinem code wird
num-pipe
mittlere Anzahl der Rohre? Denn wenn es, nach Ihrer pseudo-code würde mir schlecht Datei-Deskriptoren.Ich habe versucht, die Umsetzung Ihres code. Bitte überprüfen Sie meine editierte Frage. Ich habe den code Hinzugefügt.
Ok, danke. Lassen Sie es mich versuchen und ich werde wieder zu Ihnen.
Implementiert habe ich es bestätigen, es funktioniert. Sorry über den index Tippfehler. Wieder, es ist einfacher, nur halten Sie zwei Sätze von Rohren für alle Zeiten und drehen Sie die Schleife.
InformationsquelleAutor Christopher Neylan
Hier ist die korrekte Funktion code
if(j != 0 ){
Es könnte zu spät sein, aber Nein, nichts fehlt in diesem Zustand.
Sind Sie sicher? Sie haben
j!= 2*numPipes
im Kommentar oben die Anweisung.InformationsquelleAutor mkab
Den (verkürzten) relevante code:
Was bedeutet, dass die Eltern (controlling) - Prozesses bedeutet dies:
Aber es sollte so etwas wie dieses:
Wenn ich Sie gut verstehe, soll ich erstellen eine andere Gabel, wenn dann diese Gabel ist 0, ich check
while(command != NULL)
. Dann halte ich den gesamten code, den ich schrieb oben in der while-Befehl. Bin ich im Recht?Der code in meiner Antwort ist NICHT ein Vorschlag, wie das problem zu lösen. Es ist eine Zusammenfassung des Codes mit ein wenig Betonung auf das, was tatsächlich passiert.
Ja, ich weiß. Ist es der gleiche code wie bei mir. Ich habe nur versucht zu verstehen, was Sie sagten.Bitte überprüfen Sie meine editierte Frage. Ich habe einige code.
InformationsquelleAutor A.H.
Im Grunde, was Sie tun möchte, ist eine rekursive Funktion, wo das Kind führt den ersten Befehl und den Eltern führt die zweite, wenn keine anderen Befehle sind Links oder ruft die Funktion erneut aus.
InformationsquelleAutor Mathieu_Du
Aufbauend auf der Idee der Verwendung von maximal zwei Rohre auf ein mal erwähnt von Christopher Neylan, den ich zusammen gestellt habe pseudocode für n-Leitungen. args ist ein array von Zeichen Zeigern Größe 'args_size", das ist eine Globale variable.
InformationsquelleAutor Elizabeth Bradley