risposta-alla-domanda-sullo-sviluppo-web-bd.com

Il buffer verrà scaricato automaticamente su disco quando si chiude un processo?

Quando reindirizzo l'output di un comando a un file (ad es., echo Hello > file), tale file verrà garantito per avere tali dati subito dopo l'uscita del comando? O c'è ancora una piccola finestra tra le uscite dei comandi e i dati scritti nel file? Mi piacerebbe leggere il file subito dopo l'uscita del comando, ma non voglio leggere un file vuoto.

20
Eric

Ci sono più livelli di buffer/cache coinvolti.

  1. La cache della CPU.

    I dati vengono raccolti byte per byte e memorizzati nella cache della CPU. Se la cache della CPU è piena e i dati non sono stati acceduti per un po 'di tempo, il blocco contenente i nostri dati potrebbe essere scritto nella memoria principale. Questi sono, per la maggior parte, nascosti ai programmatori dell'applicazione.

  2. I buffer in-process.

    C'è un po 'di memoria nel processo in cui i dati vengono raccolti, quindi dobbiamo fare il minor numero possibile di richieste al sistema operativo, perché è relativamente costoso. Il processo copia i dati su questi buffer, che possono essere nuovamente supportati dalle cache della CPU, quindi non c'è alcuna garanzia che i dati vengano copiati nella memoria principale. L'applicazione deve svuotare esplicitamente questi buffer, ad esempio utilizzando fclose (3) o fsync (3). La funzione exit (3) lo fa anche prima che il processo sia terminato, mentre la funzione _exit (2) non lo fa , motivo per cui esiste un grande avviso nella pagina di manuale per quella funzione per chiamarlo solo se sai cosa stai facendo.

  3. I buffer del kernel

    Il sistema operativo mantiene quindi la propria cache, per ridurre al minimo il numero di richieste da inviare ai dischi. In particolare, questa cache non appartiene a nessun processo, quindi i dati in esso contenuti potrebbero appartenere a processi già completati e, poiché tutti gli accessi passano qui, il programma successivo vedrà i dati se è stato raggiunto qui. Il kernel scriverà questi dati sui dischi quando ha il tempo di farlo o quando richiesto esplicitamente.

  4. La cache dell'unità

    Le unità disco stesse conservano anche una cache per accelerare gli accessi. Questi sono scritti abbastanza velocemente, e c'è un comando per scrivere i restanti dati nelle cache e riportare quando è completo, che il sistema operativo utilizza al momento dell'arresto per assicurarsi che nessun dato sia lasciato non scritto prima di spegnere.

Per la tua applicazione, è sufficiente che i dati vengano registrati nei buffer del kernel (i dati effettivi potrebbero ancora vivere nella cache della CPU a questo punto e potrebbero non essere stati scritti nella memoria principale): il processo "echo" termina, che significa che qualsiasi buffer in-process deve essere stato svuotato e che i dati vengono consegnati al sistema operativo e quando si avvia una nuova procedura, è garantito che il sistema operativo restituirà gli stessi dati quando richiesto.

21
Simon Richter

Se l'applicazione non ha cache interne, le modifiche verranno immediatamente scritte nel file. Lo stesso per il tuo esempio. Il file è un'entità logica in memoria che verrà immediatamente aggiornata. Qualsiasi operazione successiva sul file vedrà le modifiche apportate dal programma.

Tuttavia , questo non significa che il cambiamento è stato scritto sul disco fisico. Le modifiche potrebbero persistere nelle cache del filesystem del sistema operativo o nelle cache dell'hardware. Per svuotare i buffer del filesystem, utilizzare il comando sync.

Mi piacerebbe leggere il file subito dopo l'uscita del comando, ma non voglio leggere un file vuoto.

Non dovresti incontrare problemi pratici qui.

22
mtak

Il buffer verrà scaricato automaticamente su disco quando si chiude un processo?

In generale la risposta è no .

Dipende dal comando. Come le altre risposte menzionano, se il comando non memorizza internamente i dati, tutti i dati saranno disponibili al termine del comando.

Ma la maggior parte, se non tutte, le librerie di I/O standard eseguono il buffer di default per impostazione predefinita (in una certa misura) e forniscono diverse garanzie sullo svuotamento automatico dei buffer quando l'applicazione si chiude.

C garantisce che un'uscita normale arrossisca i buffer . "Uscita normale" significa che exit viene chiamato - esplicitamente o restituendo da main. Tuttavia, l'uscita anormale può aggirare questa chiamata (e quindi lasciare i buffer non aggiornati).

Ecco un semplice esempio:

#include <signal.h>
#include <stdio.h>

int main() {
    printf("test");
    raise(SIGABRT);
}

Se lo compili e lo esegui, test will not dovrà necessariamente essere scritto su stdout.

Altri linguaggi di programmazione danno ancora meno garanzie: Java, per esempio, fa not auto-flush al termine del programma . Se il buffer di output contiene una linea non terminata, potrebbe quindi andare persa, a meno che System.out.flush() non sia stata chiamata esplicitamente.

Detto questo, il corpo della tua domanda chiede qualcosa di leggermente diverso: se i dati arrivano nel file affatto , dovrebbe farlo immediatamente dopo che il comando termina (soggetto alle avvertenze descritte nelle altre risposte ).

21
Konrad Rudolph

Penso che nessuna domanda risolva ancora sufficientemente questo problema:

Mi piacerebbe leggere il file subito dopo l'uscita del comando, ma non voglio leggere un file vuoto.

Come spiegano le altre risposte, un programma ben funzionante scarica i suoi buffer di file interni prima che il processo termini normalmente . In seguito i dati potrebbero ancora persistere nei buffer del kernel o dell'hardware prima che vengano scritti nella memoria persistente. Tuttavia , la semantica del file system di Linux garantisce che tutti i processi vedano il contenuto dei file nello stesso modo del kernel inclusi buffer interni 1.

Questo è in genere implementato avendo al massimo un buffer nel kernel per oggetto file e per richiedere che tutti gli accessi ai file passino attraverso questo buffer.

  • Se un processo legge un file, il kernel presenterà il contenuto del buffer al processo, se la parte del file richiesta è attualmente nel buffer; se non lo è, il kernel recupererà i dati dal supporto di archiviazione sottostante e lo inserirà nel buffer, quindi tornerà al passaggio precedente.

  • Se un processo scrive su un file, i dati vengono prima collocati nel buffer del kernel per quel file. Alla fine il contenuto del buffer verrà svuotato alla memoria. Nel frattempo l'accesso in lettura è soddisfatto dallo stesso buffer (vedi sopra).


1 Almeno per file normali, directory e collegamenti simbolici. FIFO e socket sono una questione diversa poiché il loro contenuto non viene mai memorizzato in modo persistente. Ci sono alcuni casi speciali di file regolari il cui contenuto dipende da chi sta chiedendo; gli esempi sono file in procfs e sysfs (si pensi /proc/self che è un collegamento simbolico all'ID di processo del processo che legge il collegamento simbolico).

9
David Foerster

Supponendo che il tuo comando sia eseguito da qualche programma usando la libreria di runtime C, a un certo punto dovrebbe invocare fclose per chiudere il file aperto.

La pagina man per la funzione fclose C dice:

NOTE Si noti che fclose () svuota solo i buffer di spazio utente forniti dalla libreria C. Per garantire che i dati siano archiviati fisicamente sul disco, anche i buffer del kernel devono essere scaricati, ad esempio con sync (2) o fsync (2).

e la pagina man per fflush ha la stessa nota. La pagina man di close dice:

Una chiusura positiva non garantisce che i dati siano stati salvati correttamente su disco, come il kernel che ha definito. Non è comune per un file system scaricare i buffer quando lo stream è chiuso. Se è necessario accertarsi che i dati siano archiviati fisicamente, utilizzare fsync (2). (Dipenderà dall'hardware del disco a questo punto.)

Si noti che i dati sono disponibili per altri processi anche se non sono sincronizzati con l'unità. Forse è già abbastanza buono per te.

Se sei in dubbio, scrivi un test.

5
mvw

Quando reindirizzo l'output di un comando a un file (ad es., echo Hello > file), tale file verrà garantito per avere tali dati subito dopo l'uscita del comando?

Sì. Shell apre il file di output e echo produce direttamente su di esso. Dopo che il comando è terminato, è fatto.

O c'è ancora una piccola finestra tra le uscite dei comandi e i dati scritti nel file?

Il fatto che i dati siano già presenti sui media è un'altra questione, che conta solo se c'è un guasto hardware in seguito, oppure ispeziona la partizione live con un software forense, ignorando il filesystem montato.

Mi piacerebbe leggere il file subito dopo l'uscita del comando, ma non voglio leggere un file vuoto.

Non preoccuparti, il kernel mantiene solo una vista del file, indipendentemente dalla frequenza di apertura.

3
Deduplicator

O c'è ancora una piccola finestra tra le uscite dei comandi e i dati scritti nel file?

No, non c'è.

Mi piacerebbe leggere il file subito dopo l'uscita del comando, ma non voglio leggere un file vuoto.

Puoi leggere il contenuto finale del file subito dopo che il comando è terminato, non leggerai mai il file vuoto. (In C e C++, usa il wait , waitpid , wait3 o wait4 chiamate di sistema per attendere l'uscita del programma e solo dopo leggere il file.Se si sta utilizzando una shell, un altro linguaggio di programmazione o una libreria (ad esempio la chiamata alla libreria C system o Java Process class), probabilmente usa già una di queste chiamate di sistema.)

Come hanno sottolineato altre risposte e commenti, si può finire per leggere un file vuoto dopo l'uscita del programma se il programma è uscito senza svuotare i suoi buffer di uscita interni (ad esempio a causa di _ exit , interrompe o riceve un segnale fatale, o perché è un programma Java che esce normalmente). Tuttavia non c'è nulla che puoi fare a questo punto: i dati non sparpagliati sono persi per sempre, l'attesa aggiuntiva non la recupererà.

2
pts

Come regola generale, tutti i dati di proprietà del kernel vengono mantenuti e ripuliti dal kernel, periodo. Tali dati includono dati trasferiti alla memoria del kernel da una chiamata di sistema come write(2) .

Tuttavia, se la tua applicazione (ad es. Libreria C) esegue il buffering su top di questo, il kernel ovviamente non ha idea e quindi non garantisce la sua pulizia.

Inoltre, non credo ci sia alcuna tempistica di garanzia per la pulizia: in genere, viene eseguita su un "best-effort" (leggi: "quando ho un sec ") base.

2
Mehrdad

Scusate forse aggiungendo un'altra risposta superflua, ma la maggior parte sembra focalizzarsi sull'aringa rossa del titolo della domanda. Ma per quanto posso dire, la domanda non riguarda affatto il buffering, ma questo:

Quando reindirizzo l'output di un comando a un file (ad es. Echo Hello> file), il file verrà garantito per avere tali dati subito dopo l'uscita del comando?

Sì, incondizionatamente. L'uso di ">" che stai descrivendo, insieme a "|" e "<", è il modello di elaborazione basato su pipe su cui il mondo Unix e Linux è fortemente basato. Troverai centinaia, se non migliaia di script totalmente dipendenti da questo comportamento in ogni installazione Linux.

Funziona come vuoi per progetto, e se ci fosse anche la minima possibilità di una condizione di gara, sarebbe stato risolto probabilmente decenni fa.

0
AnoE