2017-01-31 5 views
0

Ich versuche Rohre zu verstehen. Das Programm funktioniert gut (die Mutter sendet die Nachricht „Hallo“ zu seinem Kind und das Kind druckt es verstehe ich nicht zwei Dinge:.Warum funktioniert dieses Rohr?

  • irgendwann das Programm nicht halt würde, weil der das Kind lassen sagen den Schreib Descriptor und in der gleichen Zeit schließt, würde die übergeordnete schließt auch den Schreib Descriptor?

  • , warum es nicht die Deskriptoren erforderlich, nachdem sie schließen zu öffnen?


#include <stdlib.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 

int main(){ 

    int desc[2]; 
    pipe(desc); 

    int pid = fork(); 

    if(pid == 0){ 
     while(1){ 
      char buffer[100]; 
      close(desc[1]); 
      read(desc[0], buffer, 100); 
      printf("Child: recieved message - '%s'\n", buffer); 
     } 
    } 
    if(pid > 0){ 
     while(1){ 
      sleep(1); 
      char buffer[100]; 
      strcpy(buffer, "Hello, child!"); 
      close(desc[0]); 
      write(desc[1], buffer, 100); 
     } 
    } 
    return 0; 
} 

Antwort

1

So wenig Code, so viele kleinere Probleme:

#include <stdlib.h> 
#include <stdio.h> 
#include <unistd.h> 
#include <string.h> 

int main(){ 

    int desc[2]; 
    pipe(desc); 

Es gibt keine Fehlerprüfung des pipe() Anruf oder die anderen Systemaufrufe. Ich werde die meisten Möglichkeiten nicht weiter kommentieren.

int pid = fork(); 

Der Code verarbeitet tatsächlich einen Fehler fork().

if(pid == 0){ 
     while(1){ 
      char buffer[100]; 
      close(desc[1]); 

innerhalb des Dieser close() sollte nicht while Schleife sein. Es scheitert sowieso nach der ersten Iteration, also kein großer Schaden angerichtet, aber man sollte nicht immer versuchen, das zu schließen, was schon geschlossen ist. Es sollte außerhalb der Schleife verschoben werden.

  read(desc[0], buffer, 100); 

Sie wissen nicht, wie viele Daten gelesen wurden. Sie sollten auf die Ergebnisse von Operationen achten, die Daten lesen. Wenn Sie dies nicht tun, können Sie Müll verarbeiten. Außerdem erhält das Kind einen Rückgabewert von Null, wenn der Elternteil stirbt; Es gibt nichts anderes, als dass das Kind sterben könnte. Ihr Code sollte testen, wann es Zeit ist, die Schleife zu beenden.

  printf("Child: received message - '%s'\n", buffer); 

Dies setzt voraus, dass die aus der Leitung zu lesen Daten wurden null beendet. Das ist nicht immer garantiert, aber sehen Sie später für dieses Programm.

 } 
    } 
    if(pid > 0){ 
     while(1){ 
      sleep(1); 
      char buffer[100]; 
      strcpy(buffer, "Hello, child!"); 
      close(desc[0]); 

Ein weiterer fehl am Platze close(); Es sollte auch außerhalb der Schleife sein.

Sie initialisierten 14 Bytes der 100, die Sie schreiben, einschließlich eines Nullbytes als letztes dieser Bytes. Das ist Glück; Es bewahrt das Kind vor undefiniertem Verhalten. Streng genommen hat das Elternteil ein undefiniertes Verhalten; In der Praxis wird das kein Problem sein. Wahrscheinlich sollten Sie testen, dass die write() funktioniert. Wenn das Kind stirbt, erhält der Elternteil eine SIGPIPE und alles ist gut - der Elternteil bleibt auch stehen.

 } 
    } 
    return 0; 
} 

Es gibt nichts, die Prozesse von der Wiederholung auf unbestimmte Zeit zu stoppen. Sie müssen sie unterbrechen, um sie zu stoppen. Das ist keine langfristige Strategie.

Sie fragen:

  • Würde das Programm halt irgendwann nicht, weil das das Kind sagen wir mal den Schreib Descriptor schließt und in der gleichen Zeit, würde die Eltern auch die Schreib Descriptor schließen?

Der Elternteil kann seine Kopie des Schreib Beschreiber nur schließen, wenn es nicht so tut, außer wenn es austritt. Das Kind kann und schließt seine Kopie des Schreibdeskriptors beim ersten Durchlauf durch die Schleife (und schlägt fehl, wenn es dies bei nachfolgenden Schleifen versucht - es gibt EBADF in errno zurück, was auf einen schlechten Dateideskriptor hinweist. Ähnlich bei den Lesedeskriptoren Der Elternteil schließt seinen Lesedeskriptor in der ersten Schleife und endet bei jeder nachfolgenden Iteration. Der Kindknoten schließt seinen Lesedeskriptor nicht, bis er beendet wird. Es gibt keine Interferenz zwischen den Prozessen. Unmittelbar nach der fork(), bevor beide Prozesse etwas tun mehr, es gibt eine einzige allgemeine offene Dateibeschreibung mit zwei offenen Dateideskriptoren (wunderbarer Jargon, nicht wahr!) für jede Richtung Die Aufrufe close() betreffen die Dateideskriptoren, die Dateibeschreibung wird eliminiert, wenn keine Dateideskriptoren mehr vorhanden sind es

  • Warum ist es nicht erforderlich, die Deskriptoren nach dem Schließen zu öffnen?
  • Es gibt keine Möglichkeit, Closed Pipe-Dateideskriptoren erneut zu öffnen. Und jeder Prozess schließt nur das Ende der Pipe, die er nicht benutzt (was eine gute Übung ist - sogar wichtig, da ein Prozess nicht EOF bekommen wird, wenn er versucht, von einer Pipe zu lesen, wo er das Schreibende der Rohr noch offen).

    2

    Vielleicht sind einige Informationen über fork() vorhanden. Bei erfolgreicher Ausführung erstellt fork zwei Prozesse: almost identical. Der einzige Unterschied in Ihrem Fall ist der Rückgabewert der Gabelung (der Elternteil erhält die PID des Kindes und das Kind erhält 0). Daher werden die Pipes in beiden Prozessen geöffnet, und die Dateideskriptoren sind für beide gültig. Der Schlüssel hier ist, dass, was diese Deskriptoren darstellen, zu beiden Prozessen kopiert wurden.

    Also, wenn das Kind das fd schließt, zerstört es nur seinen eigenen Dateideskriptor, nicht den seines Elternteils.

    Beachten Sie jedoch, dass der Abschluss des fd außerhalb der Schleife erfolgen sollte. Es ist zwar nicht sicher (und in Ihrem Fall, vielleicht ist es nicht passiert), wenn Sie dieselbe Datei mehrmals schließen, kann Ihr Programm abstürzen.

    Verwandte Themen