Gestione in ingresso e in uscita

Questo argomento fornisce un'introduzione alle considerazioni di programmazione per la gestione di input e output e le subroutine di gestione dell'input e dell'output (I/O).

Le subroutine della libreria I/O possono inviare dati a o da dispositivi o file. Il sistema tratta i dispositivi come se fossero file I/O. Ad esempio, è necessario anche aprire e chiudere un dispositivo proprio mentre si fa un file.

Alcune subroutine utilizzano input standard e output standard come i loro canali I/O. Per la maggior parte delle subroutine, tuttavia, è possibile specificare un file diverso per la sorgente o la destinazione del trasferimento dati. Per alcune subroutine è possibile utilizzare un puntatore di file ad una struttura che contiene il nome del file; per altri è possibile utilizzare un descrittore di file (cioè il numero intero positivo assegnato al file quando viene aperto).

Le sottoroutine I/O memorizzate nella Libreria C (libc.a) forniscono I/O di flusso. Per accedere a queste sottoroutine I/E del flusso, è necessario includere il file stdio.h utilizzando la seguente istruzione:
#include <stdio.h>

Alcune delle subroutine della libreria I/O sono macro definite in un file di intestazione e alcuni sono moduli oggetto di funzioni. In molti casi la libreria contiene una macro e una funzione che fanno lo stesso tipo di operazione. Considerare quanto segue quando si decide se utilizzare la macro o la funzione:

  • Non è possibile impostare un breakpoint per una macro utilizzando il programma dbx .
  • Le macro sono di solito più veloci delle loro funzioni equivalenti perché il preprocessore sostituisce le macro con linee effettive di codice nel programma.
  • I macro risultano in codice oggetto più grande dopo essere stati compilati.
  • Le funzioni possono avere effetti collaterali da evitare.

I file, i comandi e le subroutine utilizzati nella gestione I/O forniscono le seguenti interfacce:

Basso livello
L'interfaccia di basso livello fornisce funzioni di apertura e chiusura di base per file e dispositivi.
Flusso
L'interfaccia di flusso fornisce I/O di lettura e scrittura per tubi e FIFOs.
Terminale
L'interfaccia terminale fornisce output formattato e tamponamento.
Asincrono
L'interfaccia asincrona fornisce I/O e elaborazione simultanee.
Lingua di input
L'interfaccia in ingresso in ingresso utilizza i comandi lex e yacc per generare un analizzatore lessicale e un programma di parser per l'interpretazione I/O.

Interfacce I/O di basso livello

Le interfacce I/O di basso livello sono punti di ingresso diretti in un kernel, fornendo funzioni come l'apertura dei file, la lettura e la scrittura da file, e la chiusura dei file.

Il comando line fornisce l'interfaccia che consente di leggere una riga dall'input standard e le seguenti subroutine forniscono altre funzioni I/O di basso livello:

aperto, openx o creat
Preparare un file, o altro oggetto di percorso, per la lettura e la scrittura tramite un descrittore di file assegnato
lettura, readx, readv o readvx
Leggi da un descrittore di file aperto
scrittura, writex, writev o writevx
Scrivi su un descrittore di file aperto
Chiudi
Relinquina un descrittore di file

Le subroutine open e creat impostano le voci in tre tabelle di sistema. Un descrittore di file indicizza la prima tabella, che funziona come un'area dati di processo a cui è possibile accedere tramite le subroutine di lettura e scrittura. Ogni voce in questa tabella ha un puntatore ad una voce corrispondente nella seconda tabella.

La seconda tabella è un database per sistema, o tabella di file, che consente di condividere un file aperto tra diversi processi. Le voci in questa tabella indicano se il file era aperto per la lettura, la scrittura o come un tubo, e quando il file è stato chiuso. C'è anche un offset per indicare dove avrà luogo la prossima lettura o scrittura e un puntatore finale per indicare l'ingresso alla terza tabella, che contiene una copia dell'i-node del file.

La tabella dei file contiene voci per ogni istanza di una sottoroutine aperta o create sul file, ma la tabella i-node contiene una sola voce per ogni file.

Nota: Mentre si elabora una sottoroutine aperta o creat per un file speciale, il sistema richiama sempre la sottoroutine aperta del dispositivo per consentire qualsiasi elaborazione speciale (come riavvolgere un nastro o girare su un lead modem pronto per il modem). Tuttavia, il sistema utilizza la sottoroutine close solo quando l'ultimo processo chiude il file (cioè quando la voce della tabella i-node viene deallocata). Ciò significa che un dispositivo non può mantenere o dipendere da un conteggio dei suoi utenti a meno che non venga implementato un dispositivo di utilizzo esclusivo (che impedisce il riapertura di un dispositivo prima del suo chiuso).

Quando si verifica un'operazione di lettura o scrittura, gli argomenti dell'utente e la voce della tabella dei file vengono utilizzati per impostare le seguenti variabili:

  • Indirizzo utente dell'area di destinazione I/O
  • Conteggio byte per il trasferimento
  • Posizione corrente nel file

Se il file di cui si fa riferimento è un file speciale di tipo carattere, la sottoroutine di lettura o scrittura appropriata è chiamata a trasferire i dati, oltre ad aggiornare il conteggio e la posizione attuale. In caso contrario, la posizione corrente viene utilizzata per calcolare un numero di blocco logico nel file.

Se il file è un file ordinario, il numero di blocco logico deve essere mappato ad un numero di blocco fisico. Non è necessario mappare un file speciale di tipo di blocco. Il numero di blocco fisico risultante viene utilizzato per leggere o scrivere il dispositivo appropriato.

I driver del dispositivo di blocco possono fornire la possibilità di trasferire le informazioni direttamente tra l'immagine core dell'utente e il dispositivo in blocchi di dimensioni più grandi delle richieste del chiamante senza utilizzare buffer. Il metodo implica l'impostazione di un file speciale di tipo di carattere corrispondente alla periferica raw e fornire sottoroutine di lettura e scrittura per creare un'intestazione di buffer privata, non condivisa con le informazioni appropriate. Possono essere fornite delle subroutine aperte e vicine e una sottoroutine a funzione speciale può essere chiamata per il nastro magnetico.

Interfacce I/O di flusso

Le interfacce I/O di flusso forniscono i dati come un flusso di byte che non viene interpretato dal sistema, che offre un'implementazione più efficiente per i protocolli di networking rispetto all'elaborazione delle I/O dei caratteri. Non esistono confini record quando si legge e si scrive utilizzando I/O di flusso. Ad esempio, un processo di lettura di 100 bytes da un tubo non può determinare se il processo che ha scritto i dati nel tubo ha fatto una sola scrittura di 100 bytes, o due scritture di 50 bytes, o anche se il 100 bytes proviene da due diversi processi.

Stream I/Os può essere pipe o FIFOs (first-in, file di prima uscita). I FIFOs sono simili ai tubi perché permettono ai dati di fluire solo in un modo (da sinistra a destra). Tuttavia, a un FIFO può essere dato un nome e si può accedere da processi indipendenti, diversamente da un tubo. FIFOs sono a volte indicati come named pipe. Poiché ha un nome, è possibile aprire una FIFO utilizzando la sottoroutine I/O fopen standard. Per aprire un pipe è necessario chiamare la sottoroutine pipe , che restituisce un descrittore di file, e la sottoroutine I/O fdopen standard per associare un descrittore di file aperto con un flusso I/O standard.

Nota: Le interfacce I/O del flusso sono dati buffer a livello di utente e non possono scrivere i dati fino a quando non viene eseguita la sottoroutine fclose o fflush , che potrebbe portare a risultati imprevisti quando si mescolano con I/O di file come ad esempio la lettura () o la scrittura ().

Si accede alle interfacce I/O di flusso attraverso le seguenti sottoroutine e macro:

fclose
Chiude un flusso
fedi, ferrore, clearerr o fileno
Controllare lo stato di un flusso
fflush
Scrivi tutti i caratteri attualmente tamponati da un flusso
fapri, freopen o fdopen
Aprire un flusso
fread o fwrite
Eseguire input binari
fseek, rewind, ftell, fgetpos o fsetpos
Riposiamo il puntatore del file di un flusso
getc, fgetc, getchar o getw
Ottenere un carattere o una parola da un flusso di input
gets o fgets
Ottire una stringa da un flusso
getwc, fgetwc o getwchar
Ottenere un carattere ampio da un flusso di input
getws o fgetws
Ottire una stringa da un flusso
printf, fprintf, sprintf, wsprintf, vprintf, vfprintf, vsprintf o vwsprintf
Emissione formattata di stampa
putc, putchar, fputc o putw
Scrivi un carattere o una parola a un flusso
mette o finserisce
Scrivi una stringa a un flusso
putwc, putwchar o fputwc
Scrivi un carattere o una parola a un flusso
putti o fputti
Scrivi una stringa di carattere ampio a un flusso
scanf, fscanf, sscanf o wsscanf
Convertire input formattati
setbuf, setvbuf, setbuffer o setlinebuf
Assegnare il buffering a un flusso
ungetc o ungetwc
Spingere un carattere indietro nel flusso di input

Interfacce I/O del terminale

Le interfacce I/O terminali funzionano tra un processo e il kernel, fornendo funzioni quali buffering e output formattati. Ogni terminale e pseudo - terminale ha una struttura tty che contiene l'attuale ID gruppo di processo. Questo campo identifica il gruppo di processo per ricevere i segnali associati al terminale. È possibile accedere alle interfacce I/O del terminale tramite il comando iostat , che monitora il caricamento del dispositivo di sistema I/O e il daemon uprintfd , che consente di scrivere i messaggi del kernel sulla console di sistema.

Le caratteristiche terminali possono essere abilitate o disabilitate attraverso le seguenti sottoroutine:

cfgetospeed, cfsetospeed, cfgetispeedo cfsetispeed
Ottenere e impostare i tassi di baud di input e output
ioctl
Esegue funzioni di controllo associate al terminale
termdef
Query delle caratteristiche del terminale
tcdrain
Attese per l'output da completare
tcflow
Esegue funzioni di controllo del flusso
tcflush
Elimina i dati dalla coda specificata
tcgetpgrp
Ottiene ID gruppo di processo foreground
tcsendbreak
Invia una pausa su una linea di dati seriale asincrona
tcsetattr
Imposta stato terminale
ttylock, ttywait, ttyunlocko ttylock
Funzioni di blocco tty di controllo
ttyname o isatty
Porta il nome di un terminale
ttyslot
Trova lo slot nel file utmp per l'utente corrente

Interfacce I/O asincrone

Le subroutine I/O asincrone consentono ad un processo di avviare un'operazione di I/O e di avere la subroutine di ritorno subito dopo l'avvio dell'operazione o la coda. Un'altra sottoroutine è tenuta ad attendere che l'operazione venga completata (o tornare immediatamente se l'operazione è già terminata). Ciò significa che un processo può sovrapporsi alla sua esecuzione con il suo I/O I/O o sovrapposizione tra diversi dispositivi. Anche se l'I/O asincrono non migliora sensibilmente le prestazioni per un processo che sta leggendo da un file disco e la scrittura su un altro file disco, l'I/O asincrono può fornire notevoli miglioramenti delle prestazioni per altri tipi di programmi di I/O, come i programmi che scaricano un disco su un nastro magnetico o visualizzano un'immagine su un display dell'immagine.

Sebbene non richiesto, un processo che sta eseguendo I/O asincroni può dire al kernel di notificarlo quando un descrittore specificato è pronto per l'I/O (chiamato anche I/O - driven I/O). Quando si utilizza LEGACY AIO, il kernel notifica il processo dell'utente con il segnale SIGIO. Quando si utilizza POSIX AIO, la struttura sigevent viene utilizzata dal programmatore per determinare quale segnale per il kernel utilizzare per notificare il processo utente. I segnali includono SIGIO, SIGUSR1e SIGUSR2.

Per utilizzare I/O asincroni, un processo deve effettuare le seguenti operazioni:

  1. Stabilire un gestore per il segnale SIGIO . Questo passo è necessario solo se viene richiesta la notifica da parte del segnale.
  2. Impostare l'ID di processo o l'ID del gruppo di processo per ricevere i segnali SIGIO . Questo passo è necessario solo se viene richiesta la notifica da parte del segnale.
  3. Abilitare I/O asincroni. L'amministratore di sistema di solito determina se l'I/O asincrono viene caricato (abilitato). L'abilitazione si verifica alla startup del sistema.

Vengono fornite le seguenti subroutine I/O asincrone:

aio_annullo
Annulla una o più richieste I/O asincrone in sospeso
aio_errore
Richiama lo stato di errore di una richiesta I/O asincrona
aio_fsync
Sincronizza i file asincroni.
aio_nwait
Sospende il processo di chiamata fino a quando non viene completato un certo numero di richieste I/O asincrone.
aio_letti
Letture asincrone da un descrittore di file
aio_return
Richiama lo stato di ritorno di una richiesta I/O asincrona
aio_sospendi
Sospende il processo di chiamata fino al completamento di una o più richieste I/O asincrone
aio_scrittura
Scrive in modo asincrono su un descrittore di file
lio_elenio
Iniziate un elenco di richieste I/O asincrone con una sola chiamata
poll o selezionare
Controllare lo stato I/O di più descrittori di file e code di messaggi

Per l'utilizzo con la sottoroutine poll vengono forniti i seguenti file di intestazione:

poll.h
Definisce le strutture e le bandiere utilizzate dalla subroutine poll
aio.h
Definisce la struttura e gli indicatori utilizzati dalle sottoroutine aio_read, aio_writee aio_sospendere