Eingabe-und Ausgabeverarbeitung
Dieser Abschnitt enthält eine Einführung in die Programmieraspekte für die Ein-und Ausgabeverarbeitung und die Subroutinen für die Ein-und Ausgabeverarbeitung.
Die Subroutinen der E/A-Bibliothek können Daten an oder von Einheiten oder Dateien senden. Das System behandelt Einheiten wie E/A-Dateien. Sie müssen beispielsweise auch ein Gerät wie eine Datei öffnen und schließen.
Einige Unterroutinen verwenden Standardeingabe und Standardausgabe als E/A-Kanäle. Für die meisten Unterroutinen können Sie jedoch eine andere Datei als Quelle oder Ziel der Datenübertragung angeben. Bei einigen Subroutinen können Sie einen Dateizeiger auf eine Struktur verwenden, die den Namen der Datei enthält. Bei anderen Subroutinen können Sie einen Dateideskriptor verwenden (d. h. die positive ganze Zahl, die der Datei beim Öffnen zugeordnet wird).
#include <stdio.h>Einige der E/A-Bibliothekssubroutinen sind Makros, die in einer Headerdatei definiert sind, und einige sind Objektmodule von Funktionen. In vielen Fällen enthält die Bibliothek ein Makro und eine Funktion, die denselben Operationstyp ausführen. Beachten Sie Folgendes, wenn Sie entscheiden, ob das Makro oder die Funktion verwendet werden soll:
- Mit dem Programm dbx können Sie keinen Unterbrechungspunkt für ein Makro definieren.
- Makros sind normalerweise schneller als ihre äquivalenten Funktionen, da der Vorprozessor die Makros durch tatsächliche Codezeilen im Programm ersetzt.
- Makros führen nach der Kompilierung zu einem größeren Objektcode.
- Funktionen können zu vermeiden Nebeneffekte haben.
Die bei der E/A-Verarbeitung verwendeten Dateien, Befehle und Subroutinen stellen die folgenden Schnittstellen bereit:
- Untergeordnete Ebene
- Die Low-Level-Schnittstelle bietet grundlegende Open-und Close-Funktionen für Dateien und Geräte.
- Datenstrom
- Die Datenstromschnittstelle stellt Lese-und Schreib-E/A für Pipes und FIFOs bereit.
- Datenstation
- Die Terminalschnittstelle stellt formatierte Ausgabe und Pufferung bereit.
- Asynchron
- Die asynchrone Schnittstelle ermöglicht gleichzeitige Ein-/Ausgabe und Verarbeitung.
- Eingabesprache
- Die Eingabesprache verwendet die Befehle lex und yacc , um ein lexikalisches Analyseprogramm und ein Parserprogramm für die Interpretation der Ein-/Ausgabe zu generieren.
Low-Level-E/A-Schnittstellen
Low-Level-E/A-Schnittstellen sind direkte Einstiegspunkte in einen Kernel, die Funktionen wie das Öffnen von Dateien, das Lesen und Schreiben von Dateien und das Schließen von Dateien bereitstellen.
Der Befehl line stellt die Schnittstelle bereit, mit der eine Zeile aus der Standardeingabe gelesen werden kann, und die folgenden Subroutinen stellen weitere Low-Level-E/A-Funktionen bereit:
- open, openx oder creat
- Bereiten Sie eine Datei oder ein anderes Pfadobjekt zum Lesen und Schreiben mithilfe eines zugeordneten Dateideskriptors vor.
- read, readx, readv oder readvx
- Aus einem offenen Dateideskriptor lesen
- write, writex, writev oder writevx
- In einen offenen Dateideskriptor schreiben
- Schließen
- Dateideskriptor aufgeben
Die Subroutinen open und creat richten Einträge in drei Systemtabellen ein. Ein Dateideskriptor indexiert die erste Tabelle, die als Datenbereich pro Prozess fungiert, auf den von Lese-und Schreibsubroutinen zugegriffen werden kann. Jeder Eintrag in dieser Tabelle hat einen Zeiger auf einen entsprechenden Eintrag in der zweiten Tabelle.
Die zweite Tabelle ist eine systemspezifische Datenbank oder Dateitabelle, die es ermöglicht, eine offene Datei von mehreren Prozessen gemeinsam zu nutzen. Die Einträge in dieser Tabelle geben an, ob die Datei zum Lesen, Schreiben oder als Pipe geöffnet war und wann sie geschlossen wurde. Es gibt auch einen Offset, um anzugeben, wo der nächste Lese-oder Schreibvorgang stattfinden wird, und einen endgültigen Zeiger auf den Eintrag in der dritten Tabelle, die eine Kopie des I-Node der Datei enthält.
Die Dateitabelle enthält Einträge für jede Instanz einer Subroutine open oder create für die Datei, aber die I-Node-Tabelle enthält nur einen Eintrag für jede Datei.
Wenn eine Lese-oder Schreiboperation auftritt, werden die Argumente des Benutzers und der Dateitabelleneintrag verwendet, um die folgenden Variablen festzulegen:
- Benutzeradresse des E/A-Zielbereichs
- Bytezähler für die Übertragung
- Aktuelle Position in der Datei
Wenn es sich bei der Datei, auf die verwiesen wird, um eine zeichenorientierte Gerätedatei handelt, wird die entsprechende Lese-oder Schreibsubroutine aufgerufen, um Daten zu übertragen und die Anzahl und die aktuelle Position zu aktualisieren. Andernfalls wird die aktuelle Position verwendet, um eine logische Blocknummer in der Datei zu berechnen.
Handelt es sich bei der Datei um eine normale Datei, muss die logische Blocknummer einer physischen Blocknummer zugeordnet werden. Eine blockorientierte Gerätedatei muss nicht zugeordnet werden. Die resultierende Nummer des physischen Blocks wird zum Lesen oder Schreiben der entsprechenden Einheit verwendet.
Blockeinheitentreiber können die Möglichkeit bieten, Informationen direkt zwischen dem Kernimage des Benutzers und dem Gerät in Blockgrößen zu übertragen, die so groß sind wie die Anforderungen des Anrufers, ohne Puffer zu verwenden. Die Methode umfasst die Einrichtung einer Zeichendatei, die der Roheinheit entspricht, und die Bereitstellung von Lese-und Schreibsubroutinen zum Erstellen eines privaten, nicht gemeinsam genutzten Pufferheaders mit den entsprechenden Informationen. Separate Subroutinen zum Öffnen und Schließen können bereitgestellt werden, und eine Subroutine mit Sonderfunktion kann für Magnetband aufgerufen werden.
Datenstrom-E/A-Schnittstellen
Datenstrom-E/A-Schnittstellen stellen Daten als Bytestrom bereit, der vom System nicht interpretiert wird. Dies bietet eine effizientere Implementierung für Netzprotokolle als die Zeichen-E/A-Verarbeitung. Beim Lesen und Schreiben mit Datenstrom-E/A gibt es keine Satzgrenzen. Beispielsweise kann ein Prozess, der 100 Byte aus einer Pipe liest, nicht feststellen, ob der Prozess, der die Daten in die Pipe geschrieben hat, einen einzigen Schreibvorgang von 100 Byte oder zwei Schreibvorgänge von 50 Byte ausgeführt hat oder ob die 100 Byte von zwei verschiedenen Prozessen stammen.
Datenstromein-/-ausgaben können Pipes oder FIFOs (First In/First Out-Dateien) sein. FIFOs sind Pipes ähnlich, da sie zulassen, dass die Daten nur eine Richtung (von links nach rechts) fließen. Eine FIFO-Warteschlange kann jedoch einen Namen erhalten und von nicht zugehörigen Prozessen aufgerufen werden, im Gegensatz zu einer Pipe. FIFOs werden manchmal als benannte Pipesbezeichnet. Da sie einen Namen hat, kann eine FIFO-Routine mit der Standard-E/A-Subroutine fopen geöffnet werden. Zum Öffnen einer Pipe müssen Sie die Subroutine pipe aufrufen, die einen Dateideskriptor zurückgibt, und die Standard-E/A-Subroutine fdopen aufrufen, um einen offenen Dateideskriptor einem Standard-E/A-Datenstrom zuzuordnen.
Der Zugriff auf Datenstrom-E/A-Schnittstellen erfolgt über die folgenden Subroutinen und Makros:
- fclose
- Schließt einen Datenstrom
- feof, ferror, clearerr oder fileno
- Status eines Datenstroms überprüfen
- fflush
- Alle derzeit gepufferten Zeichen aus einem Stream schreiben
- fopen, freopen oder fdopen
- Stream öffnen
- fread oder fwrite
- Binäre Eingabe ausführen
- fseek, rewind, ftell, fgetpos oder fsetpos
- Dateizeiger eines Datenstroms neu positionieren
- getc, fgetc, getchar oder getw
- Zeichen oder Wort aus einem Eingabedatenstrom abrufen
- gets oder fgets
- Zeichenfolge aus einem Stream abrufen
- getwc, fgetwc oder getwchar
- Ein Breitzeichen aus einem Eingabedatenstrom abrufen
- getws oder fgetws
- Zeichenfolge aus einem Stream abrufen
- printf, fprintf, sprintf, wsprintf, vprintf, vfprintf, vsprintf oder vwsprintf
- Formatierte Ausgabe drucken
- putc, putchar, fputc oder putw
- Ein Zeichen oder ein Wort in einen Datenstrom schreiben
- puts oder fputs
- Zeichenfolge in einen Datenstrom schreiben
- putwc, putwchar oder fputwc
- Ein Zeichen oder ein Wort in einen Datenstrom schreiben
- putws oder fputws
- Breite Zeichenfolge in einen Datenstrom schreiben
- scanf, fscanf, sscanf oder wsscanf
- Formatierte Eingabe konvertieren
- setbuf, setvbuf, setbuffer oder setlinebuf
- Pufferung einem Datenstrom zuordnen
- ungetc oder ungetwc
- Zeichen zurück in den Eingabedatenstrom schieben
E/A-Schnittstellen für Terminals
Terminal-E/A-Schnittstellen arbeiten zwischen einem Prozess und dem Kernel und stellen Funktionen wie Pufferung und formatierte Ausgabe bereit. Jedes Terminal und Pseudoterminal hat eine TTY-Struktur, die die aktuelle Prozessgruppen-ID enthält. Dieses Feld gibt die Prozessgruppe an, die die dem Terminal zugeordneten Signale empfangen soll. Auf E/A-Terminalschnittstellen kann über den Befehl iostat zugegriffen werden, der das Laden von E/A-Systemeinheiten überwacht, und über den Dämon uprintfd , der das Schreiben von Kernelnachrichten in die Systemkonsole ermöglicht.
Terminalmerkmale können über die folgenden Subroutinen aktiviert oder inaktiviert werden:
- cfgetospeed, cfsetospeed, cfgetispeedoder cfsetispeed
- Eingabe-und Ausgabebaudraten abrufen und festlegen
- ioctl
- Führt Steuerfunktionen aus, die dem Terminal zugeordnet sind
- Terminaldefinition
- Abfragenterminalmerkmale
- tcdrain
- Wartet auf Abschluss der Ausgabe
- tcflow
- Führt Ablaufsteuerungsfunktionen aus
- tcflush
- Löscht Daten aus der angegebenen Warteschlange
- tcgetpgrp
- Ruft die ID der Vordergrundprozessgruppe ab
- tcsendbreak
- Sendet einen Umbruch in einer asynchronen seriellen Datenleitung
- tcset-attribut
- Legt den Terminalstatus fest
- ttylock, ttywait, ttyunlockoder ttylocked
- TTY-Sperrfunktionen steuern
- ttyname oder isatty
- Namen eines Terminals abrufen
- ttyslot
- Sucht den Slot in der Datei utmp für den aktuellen Benutzer.
Asynchrone E/A-Schnittstellen
Asynchrone E/A-Subroutinen ermöglichen es einem Prozess, eine E/A-Operation zu starten und die Subroutine unmittelbar nach dem Start oder in der Warteschlange zurückzugeben. Eine weitere Subroutine muss warten, bis die Operation abgeschlossen ist (oder sofort zurückkehren, wenn die Operation bereits beendet ist). Dies bedeutet, dass ein Prozess seine Ausführung mit seiner Ein-/Ausgabe oder der Ein-/Ausgabe zwischen verschiedenen Einheiten überschneiden kann. Obwohl die asynchrone Ein-/Ausgabe die Leistung für einen Prozess, der von einer Plattendatei liest und in eine andere Plattendatei schreibt, nicht wesentlich verbessert, kann die asynchrone Ein-/Ausgabe erhebliche Leistungsverbesserungen für andere Typen von E/A-gesteuerten Programmen bieten, wie z. B. Programme, die eine Platte auf einem Magnetband ausgeben oder ein Bild auf einer Bildanzeige anzeigen.
Obwohl nicht erforderlich, kann ein Prozess, der asynchrone Ein-/Ausgabe ausführt, den Kernel anweisen, ihn zu benachrichtigen, wenn ein angegebener Deskriptor für Ein-/Ausgabe bereit ist (auch als signalgesteuerte Ein-/Ausgabebezeichnet). Bei Verwendung von LEGACY AIO benachrichtigt der Kernel den Benutzerprozess mit dem Signal SIGIO. Bei Verwendung von POSIX AIO wird die Struktur sigevent vom Programmierer verwendet, um zu bestimmen, welches Signal für den Kernel verwendet werden soll, um den Benutzerprozess zu benachrichtigen. Signale umfassen SIGIO, SIGUSR1und SIGUSR2.
Zur Verwendung der asynchronen Ein-/Ausgabe muss ein Prozess die folgenden Schritte ausführen:
- Erstellen Sie einen Handler für das Signal SIGIO . Dieser Schritt ist nur erforderlich, wenn eine Benachrichtigung durch das Signal angefordert wird.
- Legen Sie die Prozess-ID oder die Prozessgruppen-ID für den Empfang der SIGIO -Signale fest. Dieser Schritt ist nur erforderlich, wenn eine Benachrichtigung durch das Signal angefordert wird.
- Asynchrone Ein-/Ausgabe aktivieren. Der Systemadministrator bestimmt normalerweise, ob asynchrone Ein-/Ausgabe geladen (aktiviert) wird. Die Aktivierung erfolgt beim Systemstart.
Die folgenden asynchronen E/A-Subroutinen werden bereitgestellt:
- aio_abbrechen
- Bricht eine oder mehrere ausstehende asynchrone E/A-Anforderungen ab.
- E/A-Fehler
- Ruft den Fehlerstatus einer asynchronen E/A-Anforderung ab.
- aio_fsync
- Synchronisiert asynchrone Dateien.
- aio_nwait
- Setzt den aufrufenden Prozess aus, bis eine bestimmte Anzahl asynchroner E/A-Anforderungen abgeschlossen ist.
- aio_lesen
- Liest asynchron aus einem Dateideskriptor
- aio_rückgabe
- Ruft den Rückgabestatus einer asynchronen E/A-Anforderung ab.
- aio_aussetzen
- Setzt den aufrufenden Prozess aus, bis eine oder mehrere asynchrone E/A-Anforderungen abgeschlossen sind.
- E/A-Schreibvorgänge
- Schreibt asynchron in einen Dateideskriptor.
- lio_listio
- Leitet eine Liste asynchroner E/A-Anforderungen mit einem einzigen Aufruf ein.
- poll oder select
- E/A-Status mehrerer Dateideskriptoren und Nachrichtenwarteschlangen prüfen
Zur Verwendung mit der Subroutine poll werden die folgenden Headerdateien bereitgestellt:
- poll.h
- Definiert die Strukturen und Flags, die von der Subroutine poll verwendet werden.
- aio.h
- Definiert die Struktur und die Flags, die von den Subroutinen aio_read, aio_writeund aio_suspend verwendet werden