Mi piacerebbe sapere se le chiamate di sistema di lettura/scrittura di Linux supportano letture/scritture non sincronizzate (scritture senza aggiunta) a regioni non sovrapposte di un singolo file su disco da più thread o processi. Ciascun thread cercherà la propria regione del file e leggerà/scriverà esclusivamente da/verso questa regione, senza mai sovrapporsi alle regioni su cui operano gli altri thread.
POSIX specifica in XSH 2.9.7 che sostanzialmente tutte le funzioni di I/O sono atomiche l'una rispetto all'altra per quanto riguarda i loro effetti specificati da POSIX. Viene fornito un lungo elenco delle funzioni specifiche a cui si applica e open()
, lseek()
, read()
, write()
e close()
ci sono tutti. Pertanto,
Se due thread chiamano ciascuno una di queste funzioni, ciascuna chiamata vedrà tutti gli effetti specificati dell'altra chiamata o nessuno di essi.
Ciò non dipende da alcuna sincronizzazione esterna, anche per le operazioni sui descrittori di file associati alla stessa descrizione di file aperto.
Possono esserci più descrizioni di file aperti per lo stesso file, anche in un singolo processo (vedere, ad esempio, la pagina di manuale per open(2)). Dati più thread che eseguono read()
e write()
operazioni su regioni non sovrapposte dello stesso file regolare, tramite descrittori di file che fanno riferimento a diverse descrizioni di file aperti , POSIX non fornisce alcuna base per aspettarsi che tali operazioni interferiscano tra loro, indipendentemente dalla sincronizzazione esterna dei thread coinvolti. In pratica, funziona bene.
Dove puoi metterti nei guai è se i thread coinvolti stanno tentando di utilizzare descrittori di file che fanno riferimento alla stessa descrizione di file aperto. Questi non devono essere lo stesso valore del descrittore di file (quindi dup()
ing un descrittore di file non aiuta qui), né i thread devono appartenere allo stesso processo affinché si verifichi la situazione. Ogni descrizione di file aperta ha una singola posizione di file associata, quindi se due thread diversi stanno tentando di eseguire attività che richiedono ciascuno separatamente l'impostazione dell'offset del file e il trasferimento dei dati da o verso il file e se utilizzano la stessa descrizione del file aperto, l'atomicità delle singole chiamate di funzione non è sufficiente per garantire che le letture e le scritture vengano eseguite nelle posizioni previste. La sincronizzazione è richiesta in quello scenario.
In alternativa, come osservato da @maximegorushkin nei commenti e @bk2204 osservato in un'altra risposta, pread()
e pwrite()
le funzioni eseguono il posizionamento e il trasferimento dei dati in un'unica chiamata. Anche queste sono nell'elenco delle funzioni di I/O atomiche e superano la separazione del posizionamento dal trasferimento dei dati in base al trasferimento dei dati. Il loro utilizzo richiede un'attenzione e una contabilità extra, e ci sono scenari in cui non serve adeguatamente, ma potrebbe comunque essere fattibile per il caso particolare in questione.
Pertanto , se due thread diversi vogliono operare sullo stesso file senza sincronizzazione, l'approccio più sicuro e generale è che ognuno apra il file in modo indipendente. Non interferiranno quindi l'uno con l'altro fintanto che le loro operazioni di I/O sono limitate a regioni disgiunte del file. Anche operare su regioni sovrapposte del file non è fuori discussione, ma ciò introduce considerazioni più complesse e specifiche dell'applicazione.
Sì, questo è possibile. Il pread
e pwrite
Le funzioni consentono di leggere e scrivere da un file a un determinato offset senza modificare l'offset del file. Sono specificamente progettati per consentire la lettura e la scrittura in programmi multithread.
Dovresti notare che in violazione di POSIX, pwrite
su un descrittore di file aperto con O_APPEND
scriverà sempre fino alla fine del file.