[Avanti]  [Indietro]  [Su]  

7.3.2 Il controllo della bufferizzazione

Come accennato in sez. 7.1.4 le librerie definiscono una serie di funzioni che permettono di controllare il comportamento degli stream; se non si è specificato nulla, la modalità di buffering viene decisa autonomamente sulla base del tipo di file sottostante, ed i buffer vengono allocati automaticamente.

Però una volta che si sia aperto lo stream (ma prima di aver compiuto operazioni su di esso) è possibile intervenire sulle modalità di buffering; la funzione che permette di controllare la bufferizzazione è setvbuf, il suo prototipo è:

Restituisce zero in caso di successo, ed un valore qualunque in caso di errore, nel qual caso errno viene impostata opportunamente.

La funzione permette di controllare tutti gli aspetti della bufferizzazione; l'utente può specificare un buffer da usare al posto di quello allocato dal sistema passandone alla funzione l'indirizzo in buf e la dimensione in size.

Ovviamente se si usa un buffer specificato dall'utente questo deve essere stato allocato e rimanere disponibile per tutto il tempo in cui si opera sullo stream. In genere conviene allocarlo con malloc e disallocarlo dopo la chiusura del file; ma fintanto che il file è usato all'interno di una funzione, può anche essere usata una variabile automatica. In stdio.h è definita la macro BUFSIZ, che indica le dimensioni generiche del buffer di uno stream; queste vengono usate dalla funzione setbuf. Non è detto però che tale dimensione corrisponda sempre al valore ottimale (che può variare a seconda del dispositivo).

Dato che la procedura di allocazione manuale è macchinosa, comporta dei rischi (come delle scritture accidentali sul buffer) e non assicura la scelta delle dimensioni ottimali, è sempre meglio lasciare allocare il buffer alle funzioni di libreria, che sono in grado di farlo in maniera ottimale e trasparente all'utente (in quanto la disallocazione avviene automaticamente). Inoltre siccome alcune implementazioni usano parte del buffer per mantenere delle informazioni di controllo, non è detto che le dimensioni dello stesso coincidano con quelle su cui viene effettuato l'I/O.




Valore Modalità




_IONBF unbuffered
_IOLBF line buffered
_IOFBF fully buffered



Tabella 7.5: Valori del parametro mode di setvbuf per l'impostazione delle modalità di bufferizzazione.

Per evitare che setvbuf imposti il buffer basta passare un valore NULL per buf e la funzione ignorerà il parametro size usando il buffer allocato automaticamente dal sistema. Si potrà comunque modificare la modalità di bufferizzazione, passando in mode uno degli opportuni valori elencati in tab. 7.5. Qualora si specifichi la modalità non bufferizzata i valori di buf e size vengono sempre ignorati.

Oltre a setvbuf le glibc definiscono altre tre funzioni per la gestione della bufferizzazione di uno stream: setbuf, setbuffer e setlinebuf; i loro prototipi sono:

tutte queste funzioni sono realizzate con opportune chiamate a setvbuf e sono definite solo per compatibilità con le vecchie librerie BSD. Infine le glibc provvedono le funzioni non standard10 __flbf e __fbufsize che permettono di leggere le proprietà di bufferizzazione di uno stream; i cui prototipi sono:

Come già accennato, indipendentemente dalla modalità di bufferizzazione scelta, si può forzare lo scarico dei dati sul file con la funzione fflush, il suo prototipo è:

Restituisce zero in caso di successo, ed EOF in caso di errore, impostando errno a EBADF se stream non è aperto o non è aperto in scrittura, o ad uno degli errori di write.

anche di questa funzione esiste una analoga fflush_unlocked11 che non effettua il blocco dello stream.

Se stream è NULL lo scarico dei dati è forzato per tutti gli stream aperti. Esistono però circostanze, ad esempio quando si vuole essere sicuri che sia stato eseguito tutto l'output su terminale, in cui serve poter effettuare lo scarico dei dati solo per gli stream in modalità line buffered; per questo motivo le glibc supportano una estensione di Solaris, la funzione _flushlbf, il cui prototipo è:

Si ricordi comunque che lo scarico dei dati dai buffer effettuato da queste funzioni non comporta la scrittura di questi su disco; se si vuole che il kernel dia effettivamente avvio alle operazioni di scrittura su disco occorre usare sync o fsync (si veda sez. 6.3.3).

Infine esistono anche circostanze in cui si vuole scartare tutto l'output pendente; per questo si può usare fpurge, il cui prototipo è:

Restituisce zero in caso di successo, ed EOF in caso di errore.

La funzione scarta tutti i dati non ancora scritti (se il file è aperto in scrittura), e tutto l'input non ancora letto (se è aperto in lettura), compresi gli eventuali caratteri rimandati indietro con ungetc.


[Avanti]  [Indietro]  [Su]  
© 2000-2003 Simone Piccardi
Pubblicazione web curata da Mirko Maischberger