Unter Linux ist eine Pipe ein Kommunikationsmechanismus, der die Ausgabe eines Programms direkt mit der Eingabe eines anderen Programms verbindet. Im Wesentlichen ist eine Pipe auch eine Art Datei, unterscheidet sich jedoch von einer allgemeinen Datei. Die spezifischen Erscheinungsformen von Pipes sind: Die Größe der Pipe wird begrenzt und der Lesevorgang kann funktionieren schneller als Der Schreibvorgang ist schnell.
Die Betriebsumgebung dieses Tutorials: Linux7.3-System, Dell G3-Computer.
Pipeline ist eine sehr wichtige Kommunikationsmethode unter Linux. Sie verbindet die Ausgabe eines Programms direkt mit der Eingabe eines anderen Programms. Pipes beziehen sich oft auf unbenannte Pipes und können nur zwischen verwandten Prozessen verwendet werden. Dies ist der größte Unterschied zwischen ihnen und benannten Pipes.
Die berühmte Pipe heißt Named Pipe oder FIFO (First In, First Out) und kann mit der Funktion mkfifo() erstellt werden.
Der Implementierungsmechanismus von Linux-Pipes
Unter Linux sind Pipes ein sehr häufig verwendeter Kommunikationsmechanismus. Im Wesentlichen ist eine Pipe auch eine Art Datei, unterscheidet sich jedoch von einer allgemeinen Datei. Pipes können zwei Probleme bei der Verwendung von Dateien für die Kommunikation überwinden, insbesondere wie folgt:
Begrenzen Sie die Größe der Pipe. Tatsächlich ist eine Pipe ein Puffer fester Größe. Unter Linux beträgt die Größe dieses Puffers 1 Seite oder 4 KB, sodass seine Größe nicht wie eine Datei unkontrolliert wächst. Die Verwendung eines einzelnen festen Puffers kann ebenfalls zu Problemen führen, z. B. wenn die Pipe während des Schreibens voll wird. In diesem Fall werden nachfolgende write()-Aufrufe an die Pipe standardmäßig blockiert und darauf gewartet, dass einige Daten gelesen werden, sodass genügend Platz geschaffen wird für den write()-Aufruf zum Schreiben.
Der Lesevorgang kann auch schneller ablaufen als der Schreibvorgang. Die Pipe wird leer, wenn alle aktuellen Prozessdaten gelesen wurden. Wenn dies geschieht, blockiert ein nachfolgender read()-Aufruf standardmäßig und wartet darauf, dass einige Daten geschrieben werden, wodurch das Problem gelöst wird, dass read()-Aufrufe das Dateiende zurückgeben.
Hinweis: Das Lesen von Daten aus der Pipe ist ein einmaliger Vorgang. Sobald die Daten gelesen wurden, werden sie aus der Pipe verworfen, wodurch Platz zum Schreiben weiterer Daten frei wird.
1. Die Struktur der Pipeline
Unter Linux verwendet die Implementierung der Pipeline keine spezielle Datenstruktur, sondern basiert auf der Dateistruktur des Dateisystems und dem Indexknoten-Inode des VFS. Dies wird dadurch erreicht, dass zwei Dateistrukturen auf denselben temporären VFS-Indexknoten verweisen, der wiederum auf eine physische Seite verweist.
2. Lesen und Schreiben von Pipes
Der Quellcode der Pipeline-Implementierung befindet sich in fs/pipe.c. Es gibt viele Funktionen in pipe.c, von denen zwei wichtiger sind, nämlich die Pipe-Lesefunktion „pipe_read“. () und Pipe-Schreibfunktion pipe_wrtie(). Die Pipe-Schreibfunktion schreibt Daten, indem sie Bytes in den physischen Speicher kopiert, auf den der VFS-Indexknoten zeigt, während die Pipe-Lesefunktion Daten liest, indem sie Bytes in den physischen Speicher kopiert. Natürlich muss der Kernel einen bestimmten Mechanismus verwenden, um den Zugriff auf die Pipe zu synchronisieren. Dazu verwendet der Kernel Sperren, Warteschlangen und Signale.
Wenn der Schreibprozess in die Pipe schreibt, verwendet er die Standardbibliotheksfunktion write(). Das System kann die Dateistruktur der Datei anhand des von der Bibliotheksfunktion übergebenen Dateideskriptors ermitteln. Die Dateistruktur gibt die Adresse der Funktion an, die zum Ausführen von Schreibvorgängen verwendet wird (dh die Schreibfunktion). Daher ruft der Kernel diese Funktion auf, um den Schreibvorgang abzuschließen. Bevor die Schreibfunktion Daten in den Speicher schreibt, muss sie zunächst die Informationen im VFS-Indexknoten überprüfen. Gleichzeitig kann die eigentliche Speicherkopierarbeit nur durchgeführt werden, wenn die folgenden Bedingungen erfüllt sind:
Es ist genug vorhanden Platz im Speicher, um alle Anforderungen zu erfüllen.
Der Speicher wird vom Leseprogramm nicht gesperrt.
Wenn die oben genannten Bedingungen gleichzeitig erfüllt sind, sperrt die Schreibfunktion zunächst den Speicher und kopiert dann die Daten aus dem Adressraum des Schreibvorgangs in den Speicher. Andernfalls ruht der Schreibprozess in der Warteschlange des VFS-Indexknotens. Als Nächstes ruft der Kernel den Scheduler auf und der Scheduler wählt andere auszuführende Prozesse aus. Der Schreibvorgang befindet sich tatsächlich in einem unterbrechbaren Wartezustand. Wenn im Speicher genügend Platz für die geschriebenen Daten vorhanden ist oder der Speicher entsperrt ist, wird der Schreibvorgang zu diesem Zeitpunkt aktiviert das Signal. Nachdem die Daten in den Speicher geschrieben wurden, wird der Speicher entsperrt und alle auf dem Indexknoten schlafenden Leseprozesse werden geweckt.
Der Lesevorgang der Pfeife ähnelt dem Schreibvorgang. Abhängig vom Öffnungsmodus der Datei oder Pipe kann ein Prozess jedoch sofort eine Fehlermeldung zurückgeben, wenn keine Daten vorhanden sind oder der Speicher gesperrt ist, anstatt den Prozess zu blockieren. Im Gegenteil, der Prozess kann in der Warteschlange des Indexknotens schlafen und darauf warten, dass der Schreibprozess Daten schreibt. Wenn alle Prozesse den Pipe-Vorgang abgeschlossen haben, wird der Inode der Pipe verworfen und die gemeinsam genutzten Datenseiten werden freigegeben.
Da die Implementierung von Pipelines den Betrieb vieler Dateien erfordert, werden Sie es nicht schwer finden, es zu verstehen, wenn die Leser mit dem Dateisystem fertig sind und dann den Code in pipe.c lesen.
Linux-Pipes sind einfacher zu erstellen und zu verwenden, einfach weil sie weniger Parameter erfordern. Um das gleiche Ziel der Pipe-Erstellung wie unter Windows, Linux und UNIX zu erreichen, verwenden Sie den folgenden Codeausschnitt:
Erstellen einer Linux Named Pipe
int fd1[2]; if(pipe(fd1)) { printf("pipe() FAILED: errno=%d",errno); return 1; }
Linux-Pipes haben eine Begrenzung der Größe eines Schreibvorgangs vor dem Blockieren. Der speziell für jede Pipe verwendete Puffer auf Kernelebene beträgt genau 4096 Byte. Ein Schreibvorgang, der größer als 4 KB ist, wird blockiert, es sei denn, der Leser löscht die Pipe. Dies stellt keine wirkliche Einschränkung dar, da Lese- und Schreibvorgänge in unterschiedlichen Threads implementiert werden.
Linux unterstützt auch Named Pipes. Ein früher Kommentator dieser Zahlen schlug vor, dass ich der Fairness halber die Named Pipes von Linux mit den Named Pipes von Windows vergleiche. Ich habe ein anderes Programm geschrieben, das Named Pipes unter Linux verwendet. Ich habe festgestellt, dass es unter Linux keinen Unterschied in den Ergebnissen für benannte und unbenannte Pipes gab.
Linux-Pipes sind viel schneller als Windows 2000-Named Pipes, und Windows 2000-Named Pipes sind viel schneller als Windows XP-Named Pipes.
Beispiel:
#include<stdio.h> #include<unistd.h> int main() { int n,fd[2]; // 这里的fd是文件描述符的数组,用于创建管道做准备的 pid_t pid; char line[100]; if(pipe(fd)<0) // 创建管道 printf("pipe create error/n"); if((pid=fork())<0) //利用fork()创建新进程 printf("fork error/n"); else if(pid>0){ //这里是父进程,先关闭管道的读出端,然后在管道的写端写入“hello world" close(fd[0]); write(fd[1],"hello word/n",11); } else{ close(fd[1]); //这里是子进程,先关闭管道的写入端,然后在管道的读出端读出数据 n= read(fd[0],line,100); write(STDOUT_FILENO,line,n); } exit(0); }
Empfohlenes Lernen: Linux-Video-Tutorial
Das obige ist der detaillierte Inhalt vonWas ist eine Linux-Pipeline?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!