Frage

Ich interessiere mich für das Schreiben getrenntes Programmmodule, die als unabhängige Threads laufen, die ich mit Rohren Haken zusammen könnte. Die Motivation wäre, ich könnte jedes Modul vollständig unabhängig schreiben und testen, vielleicht sogar in verschiedenen Sprachen schreiben, oder die verschiedenen Module auf verschiedenen Rechnern laufen. Es gibt eine Vielzahl von Möglichkeiten. Ich habe für eine Weile benutzt Rohrleitungen, aber ich bin nicht vertraut mit den Nuancen seines Verhaltens.

  • Es scheint, wie die Empfängerseite wird warten Eingang blockieren, was ich erwarten würde, aber der Senden manchmal Endblock warten, dass jemand aus dem Stream zu lesen?
  • Wenn ich ein EOF in den Stream schreiben kann ich auch weiterhin halten schriftlich zu diesem Strom, bis ich es in der Nähe?
  • Gibt es Unterschiede im Verhalten benannt und unbenannte Pipes?
  • Ist es egal, welches Ende des Rohres I mit Named Pipes zuerst öffnen?
  • Ist das Verhalten von Rohren konsistent zwischen verschiedenen Linux-Systemen?
  • Ist das Verhalten der Rohre auf der Schale hängt ich verwende oder die Art, wie ich es so konfiguriert haben?
  • Gibt es noch andere Fragen sollte ich oder Fragen fragen, ich sollte bewusst sein, wenn ich will auf diese Weise Rohre benutzen?
War es hilfreich?

Lösung

Wow, das ist eine Menge Fragen. Mal sehen, ob ich kann alles abdecken ...

  

Es scheint, wie die Empfängerseite wird   Block für die Eingabe wartet, den ich   erwarten

Sie erwarten, richtig ein tatsächlicher ‚lesen‘ Anruf wird blockiert, bis etwas da ist. Aber ich glaube, es gibt einige C-Funktionen, die Sie zu ‚Peek‘ ermöglichen werden, was (und wie viel) in der Leitung warten. Leider weiß ich nicht mehr, wenn diese Blöcke als auch.

  

wird das Senden Endblock manchmal   warten, dass jemand von dem lesen   Strom

Nein, niemals blockieren senden. Denken Sie an den Auswirkungen, wenn diese ein Rohr über das Netzwerk auf einem anderen Computer. Würden Sie (durch möglicherweise hohe Latenz) für den anderen Computer warten soll, reagieren, dass sie es empfangen? Nun ist dies ein anderer Fall, wenn der Leser Griff des Ziels geschlossen wurde. In diesem Fall sollten Sie einige Fehler haben Überprüfung, dass zu behandeln.

  

Wenn ich ein EOF in den Stream schreiben kann ich   halten weiterhin an diesen Strom zu schreiben   bis ich es schließen

Ich würde denken, dies hängt davon ab, welche Sprache Sie verwenden und deren Umsetzung von Rohren. In C, würde ich nein sagen. In einem Linux-Shell, würde ich sagen, ja. Jemand anderes mit mehr Erfahrung müßte diese Frage beantworten.

  

Gibt es Unterschiede im Verhalten   benannt und unbenannte Pipes?   Soweit ich weiß, ja. Allerdings habe ich nicht viel Erfahrung mit vs nicht namentlich genannt. Ich glaube, der Unterschied ist:

  • Single Richtung vs Bidirektionale Kommunikation
  • Lesen und Schreiben auf die "in" und "out" Ströme von einem Thread
  

Ist es egal, welches Ende des Rohres I   Öffnen Sie zunächst mit Named Pipes?

Generell nein, aber Sie könnten Probleme bei der Initialisierung laufen versuchen, die Fäden miteinander zu erstellen und zu verknüpfen. Sie müssen einen Haupt-Thread haben, die alle Unter Threads erstellt und synchronisiert ihre jeweiligen Rohre miteinander.

  

Ist das Verhalten von Rohren im Einklang   zwischen den verschiedenen Linux-Systemen?

Auch hier hängt dies von welcher Sprache, aber in der Regel ja. Schon mal was von POSIX gehört? Das ist der Standard (zumindest für Linux, Windows hat seine eigene Sache).

  

Ist das Verhalten der Rohre hängen   auf der Schale Ich verwende oder die Art und Weise Ich habe   konfiguriert es?

Dies ist immer in ein wenig mehr von einer Grauzone. Die Antwort sollte , da die Schale sollte im Wesentlichen nicht sein sein System Anrufe. Doch alles bis zu diesem Punkt ist zu gewinnen.

  

Gibt es weitere Fragen, die ich sollte   fragen

Die Fragen, die Sie gefragt haben zeigt, dass Sie ein anständiges Verständnis des Systems haben. Halten Sie die Erforschung und den Schwerpunkt auf welcher Ebene Sie gehen auf zu arbeiten (Shell, C, usw.). Sie werden viel mehr lernen, indem es einfach, obwohl versuchen.

Andere Tipps

Das ist alles basiert auf einem UNIX-artiges System; Ich bin nicht vertraut mit dem spezifischen Verhalten von neueren Versionen von Windows.

Es scheint, wie die Empfangsseite für die Eingabe wartet blockieren, was ich erwarten würde, aber der Senden manchmal Endblock warten, dass jemand aus dem Stream zu lesen?

Ja, obwohl auf einer modernen Maschine kann es nicht oft passieren. Das Rohr hat einen Zwischenpuffer, der können möglicherweise füllen. Ist dies der Fall, wird die Schreibseite des Rohres in der Tat blockieren. Aber wenn man darüber nachdenkt, gibt es nicht viele Dateien, die diese groß genug sind, zu riskieren.

Wenn ich ein EOF in den Stream schreiben kann ich zu diesem Strom zu schreiben halte weiter, bis ich es schließen?

Um, meinen Sie wie ein CTRL-D, 0x04? Sicher, solange der Strom auf diese Weise eingerichtet ist. Viz.

506 # cat | od -c
abc
^D
efg
0000000    a   b   c  \n 004  \n   e   f   g  \n                        
0000012

Gibt es Unterschiede im Verhalten benannt und unbenannte Pipes?

Ja, aber sie sind subtil und die Umsetzung abhängig. Die größte ist, dass Sie eine Named Pipe schreiben kann, bevor das andere Ende läuft; mit unbenannte Pipes, erhalten die Datei-Deskriptoren während des fork / exec Prozess geteilt, so gibt es keine Möglichkeit, den vorübergehenden Puffer ohne die Prozesse sind bis zugreifen.

Ist es egal, welches Ende des Rohres I mit Named Pipes zuerst öffnen?

Nein.

Ist das Verhalten von Rohren konsistent zwischen verschiedenen Linux-Systemen?

Im Grunde ja. Puffergrößen usw. variieren kann.

Ist das Verhalten der Rohre auf der Schale hängt ich verwende oder die Art, wie ich es so konfiguriert haben?

Nein. Wenn Sie ein Rohr erstellen, unter der Decke, was passiert, ist Ihre Eltern-Prozess (die Shell) ein Rohr erzeugt, die ein Paar Filedeskriptoren hat, dann tut eine Gabel exec wie diese Pseudo-Code:

Eltern :

create pipe, returning two file descriptors, call them fd[0] and fd[1]
fork write-side process
fork read-side process

Write-Seite :

close fd[0]
connect fd[1] to stdout
exec writer program

Lesen-Seite :

close fd[1]
connect fd[0] to stdin
exec reader program

Gibt es weitere Fragen, die ich stellen soll, oder Fragen soll mir bewusst sein, wenn ich will auf diese Weise Rohre benutzen?

Ist alles, was Sie wie diese geht zu legen, wirklich in einer Linie zu tun? Wenn nicht, sollten Sie über eine allgemeinere Architektur denken. Aber die Erkenntnis, dass durch die „enge“ Schnittstelle eines Rohres in Wechselwirkung viele getrennte Prozesse, die wünschenswert ist, ist ein guter.

[Aktualisiert: Ich hatte den Dateideskriptor Indizes zunächst umgekehrt. Sie sind jetzt korrekt, siehe man 2 pipe.]

Wie Dashogun und Charlie Martin erwähnt, ist dies eine große Frage. Einige Teile ihrer Antworten sind ungenau, also werde ich auch beantworten.

  

Ich interessiere mich für das Schreiben getrenntes Programmmodule, die als unabhängige Threads laufen, die ich mit Rohren Haken zusammen könnte.

vorsichtig sein, zu versuchen, Rohre als Kommunikationsmechanismus zwischen Threads eines einzigen Prozesses zu verwenden. Da müßten Sie beide lesen und schreiben Ende des Rohres offen in einem einzigen Prozess, würden Sie nie die EOF (Null-Bytes) Anzeige erhalten.

Wenn Sie wirklich auf Prozesse beziehen waren, dann ist dies die Grundlage des klassischen Unix-Ansatz für den Aufbau-Tools. Viele der Standard-Unix-Programme sind Filter, die von der Standardeingabe lesen, verwandeln es irgendwie, und schreiben das Ergebnis auf der Standardausgabe. Zum Beispiel tr, sort, grep und cat sind alle Filter, um nur einige zu nennen. Dies ist ein ausgezeichnetes Paradigma zu folgen, wenn die Daten, die Sie erlauben es manipulieren. Nicht alle Datenmanipulationen sind förderlich für diesen Ansatz, aber es gibt viele, die sind.

  

Die Motivation wäre, dass ich schreiben konnte und jedes Modul testen völlig unabhängig, vielleicht sogar schreiben sie in verschiedenen Sprachen, oder die verschiedenen Module auf verschiedenen Maschinen ausgeführt werden.

Gute Punkte. Seien Sie sich bewusst, dass es nicht wirklich ein Rohr Mechanismus zwischen den Maschinen ist, wenn Sie in der Nähe es mit Programmen wie rsh bekommen können oder (besser) ssh. Jedoch intern, solche Programme können lokale Daten aus den Rohren lesen und diese Daten an entfernten Rechner senden, aber sie kommunizieren zwischen Maschinen über die Steckdosen, die nicht Rohre verwenden.

  

Es gibt eine Vielzahl von Möglichkeiten. Ich habe für eine Weile benutzt Rohrleitungen, aber ich bin nicht vertraut mit den Nuancen seines Verhaltens.

OK; Fragen zu stellen, ist eine (gut) Art und Weise zu lernen. Experimenting ist eine andere, natürlich.

  

Es scheint, wie die Empfangsseite für die Eingabe wartet blockieren, was ich erwarten würde, aber der Senden manchmal Endblock warten, dass jemand aus dem Stream zu lesen?

Ja. Es gibt eine Grenze für die Größe eines Rohrpuffers. Herkömmlicherweise war dies recht klein - 4096 oder 5120 waren gemeinsame Werte. Sie können feststellen, dass moderne Linux einen größeren Wert verwendet. Sie können fpathconf() und _PC_PIPE_BUF, um herauszufinden, die Größe eines Rohrpuffer verwenden. POSIX erfordert nur den Puffer 512 zu sein (das heißt, _POSIX_PIPE_BUF ist 512).

  

Wenn ich schreibe ein EOF zum Stream kann mich mit dem Schreiben weiter halten zu diesem Strom, bis ich es in der Nähe?

Technisch gibt es keine Möglichkeit, EOF in einen Stream zu schreiben; Sie schließen das Rohr Descriptor EOF anzuzeigen. Wenn Sie Steuer-D oder Steuer-Z als EOF-Zeichen denken, dann die ganz normale Zeichen sind so weit wie Rohre betroffen sind - sie nur einen Effekt wie EOF haben, wenn an einem Terminal eingegeben, die im kanonischen Modus läuft (gekocht oder normal).

  

Gibt es Unterschiede im Verhalten benannt und unbenannte Pipes?

Ja und nein. Die größten Unterschiede sind, dass unbenannte Rohre durch ein Verfahren eingestellt werden muss und kann nur von diesem Prozess und Kindern verwendet werden, die diesen Prozess als einen gemeinsamen Vorfahren teilen. Im Gegensatz dazu Named Pipes kann durch zuvor unassociated Prozesse verwendet werden. Der nächste große Unterschied ist eine Folge der ersten; mit einem ungenannten Rohr, erhalten Sie wieder zwei Dateideskriptoren aus einer einzigen Funktion (System) nennen, pipe() aber öffnen Sie ein FIFO oder Named Pipe die reguläre open() Funktion. (Jemand muss einen FIFO mit dem mkfifo() Aufruf erstellen, bevor Sie es öffnen können, unbenannte Rohre brauchen keine solche vorherigen Setup.) Sobald Sie jedoch einen Dateideskriptor geöffnet haben, gibt es sehr wenig Unterschied zwischen einem NamenRohr und ein ungenanntes Rohr.

  

Ist es egal, welches Ende des Rohres I mit Named Pipes zuerst öffnen?

Nein. Der erste Prozess zum Öffnen des FIFO wird (normalerweise) blockieren, bis es ein Verfahren mit dem anderen Ende offen ist. Wenn Sie öffnen es für das Lesen und Schreiben (einem herkömmlichen, aber möglich), dann werden Sie nicht blockiert; wenn Sie die O_NONBLOCK Flag verwenden, werden Sie nicht blockiert werden.

  

Ist das Verhalten von Rohren konsistent zwischen verschiedenen Linux-Systemen?

Ja. Ich habe nicht gehört oder erlebt Probleme mit Rohren auf einem der Systeme, in denen ich sie verwendet haben.

  

Ist das Verhalten der Rohre auf der Schale hängt ich verwende oder die Art, wie ich es so konfiguriert haben?

Nein: Rohre und FIFOs sind unabhängig von der verwendeten Shell

.
  

Gibt es weitere Fragen, die ich stellen soll, oder Fragen soll mir bewusst sein, wenn ich auf diese Weise Rohre verwenden?

Denken Sie daran, dass Sie das Lesen Ende eines Rohres in den Prozess schließen müssen, die, und das Schreibende des Rohres in dem Prozess wird das Schreiben, das Lesen wird. Wenn Sie eine bidirektionale Kommunikation über Leitungen möchten, verwenden Sie zwei separate Leitungen. Wenn Sie komplizierte Sanitär-Arrangements erstellen, passen sie von Deadlock - es ist möglich. Eine lineare Pipeline nicht Deadlock jedoch nicht (obwohl, wenn der erste Prozess seinen Ausgang nie schließt, können die nachgelagerten Prozesse auf unbestimmte Zeit warten).


Ich beobachtete sowohl über als auch in den Kommentaren zu anderen Antworten, die Rohrpuffer klassisch begrenzt sind ziemlich kleine Größen. @Charlie Martin Gegen kommentierte, dass einige Versionen von Unix haben dynamische Rohrpuffer und diese können ziemlich groß sein.

Ich bin mir nicht sicher, welche die er im Sinne hat. Ich benutzte das Testprogramm, das folgt auf Solaris, AIX, HP-UX, MacOS X, Linux und Cygwin / Windows XP (unten Ergebnisse):

#include <unistd.h>
#include <signal.h>
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

static const char *arg0;

static void err_syserr(char *str)
{
    int errnum = errno;
    fprintf(stderr, "%s: %s - (%d) %s\n", arg0, str, errnum, strerror(errnum));
    exit(1);
}

int main(int argc, char **argv)
{
    int pd[2];
    pid_t kid;
    size_t i = 0;
    char buffer[2] = "a";
    int flags;

    arg0 = argv[0];

    if (pipe(pd) != 0)
        err_syserr("pipe() failed");
    if ((kid = fork()) < 0)
        err_syserr("fork() failed");
    else if (kid == 0)
    {
        close(pd[1]);
        pause();
    }
    /* else */
    close(pd[0]);
    if (fcntl(pd[1], F_GETFL, &flags) == -1)
        err_syserr("fcntl(F_GETFL) failed");
    flags |= O_NONBLOCK;
    if (fcntl(pd[1], F_SETFL, &flags) == -1)
        err_syserr("fcntl(F_SETFL) failed");
    while (write(pd[1], buffer, sizeof(buffer)-1) == sizeof(buffer)-1)
    {
        putchar('.');
        if (++i % 50 ==  0)
            printf("%u\n", (unsigned)i);
    }
    if (i % 50 !=  0)
        printf("%u\n", (unsigned)i);
    kill(kid, SIGINT);
    return 0;
}

würde ich gespannt sein, zusätzliche Ergebnisse von anderen Plattformen zu bekommen. Hier sind die Größen I gefunden. Alle Ergebnisse sind größer als ich erwartet hatte, ich muss gestehen, aber Charlie und ich kann diskutieren die Bedeutung von ‚ziemlich groß‘ sein, wenn es darum geht, Größen zu puffern.

  • 8196 - HP-UX 11.23 für IA-64 (fcntl (F_SETFL) nicht)
  • 16384 - Solaris 10
  • 16384 - MacOS X 10.5 (O_NONBLOCK nicht funktionierte, obwohl fcntl (F_SETFL) versäumte nicht)
  • 32768 - AIX 5.3
  • 65536 - Cygwin / Windows XP (O_NONBLOCK nicht funktionierte, obwohl fcntl (F_SETFL) versäumte nicht)
  • 65536 - SuSE Linux 10 (und CentOS) (fcntl (F_SETFL) nicht)

Ein Punkt, der aus diesen Tests klar ist, dass O_NONBLOCK mit Rohren auf einigen Plattformen arbeitet und nicht auf andere.

Das Programm erstellt eine Pfeife und Gabeln. Das Kind schließt das Schreibende des Rohres, und geht dann zu schlafen, bis er ein Signal bekommt - das ist, was Pause () der Fall ist. Die Mutter dann schließt das Leseende des Rohres, und setzt die Flags auf dem Deskriptor schreiben, so dass es nicht auf einem Versuch blockiert wird auf einem Vollrohr zu schreiben. Es macht dann eine Schleife, zu einem Zeitpunkt, um ein Zeichen zu schreiben, und das Drucken eines Punktes für jedes Zeichen geschrieben, und eine Zählung und Newline alle 50 Zeichen. Wenn es ein Schreib Problem (Puffer voll, da das Kind nichts zu lesen) erkennt, die Schleife beendet, schreibt die endgültige Anzahl und tötet das Kind.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top