I file mappati in memoria possono essere utilizzati per sostituire l'accesso in lettura / scrittura o per supportare la condivisione simultanea. Quando li usi per un meccanismo, ottieni anche l'altro.
Piuttosto che cercare, scrivere e leggere in giro in un file, lo mappi nella memoria e accedi semplicemente ai bit dove ti aspetti che siano.
Questo può essere molto utile e, a seconda dell'interfaccia della memoria virtuale, può migliorare le prestazioni. Il miglioramento delle prestazioni può verificarsi perché il sistema operativo ora riesce a gestire questo precedente "file I / O" insieme a tutti gli altri accessi alla memoria programmatica e può (in teoria) sfruttare gli algoritmi di paging e così via che sta già utilizzando per supportare memoria virtuale per il resto del programma. Tuttavia, dipende dalla qualità del sistema di memoria virtuale sottostante. Aneddoti che ho sentito dire che i sistemi di memoria virtuale Solaris e * BSD possono mostrare miglioramenti delle prestazioni migliori rispetto al sistema VM di Linux, ma non ho dati empirici per supportarlo. YMMV.
La concorrenza entra in gioco quando si considera la possibilità che più processi utilizzino lo stesso "file" attraverso la memoria mappata. Nel modello di lettura / scrittura, se due processi scrivevano nella stessa area del file, si poteva essere praticamente certi che uno dei dati del processo sarebbe arrivato nel file, sovrascrivendo i dati dell'altro processo. Otterresti uno o l'altro, ma non qualche strana mescolanza. Devo ammettere che non sono sicuro che questo sia un comportamento imposto da qualsiasi standard, ma è qualcosa su cui potresti fare affidamento. (In realtà è una buona domanda di follow-up!)
Nel mondo mappato, al contrario, immagina due processi entrambi di "scrittura". Lo fanno facendo "archivi di memoria", che si traducono in O / S che impagina i dati su disco - alla fine. Ma nel frattempo ci si può aspettare che si verifichino scritture sovrapposte.
Ecco un esempio. Supponiamo che io abbia due processi che scrivono entrambi 8 byte all'offset 1024. Il processo 1 scrive "11111111" e il processo 2 scrive "22222222". Se usano l'I / O di file, allora puoi immaginare, in fondo all'O / S, ci sia un buffer pieno di 1 e un buffer pieno di 2, entrambi diretti nella stessa posizione sul disco. Uno di loro arriverà per primo e l'altro il secondo. In questo caso, vince il secondo. Tuttavia , se utilizzo l'approccio ai file mappati in memoria, il processo 1 andrà in un archivio di memoria di 4 byte, seguito da un altro archivio di memoria di 4 byte (supponiamo che non sia la dimensione massima dell'archivio di memoria). Il processo 2 farà la stessa cosa. In base a quando vengono eseguiti i processi, puoi aspettarti di vedere uno dei seguenti:
11111111
22222222
11112222
22221111
La soluzione a questo problema è usare l'esclusione reciproca esplicita, che è probabilmente una buona idea in ogni caso. In ogni caso, ti stavi facendo affidamento sull'O / S per fare "la cosa giusta" nel caso di I / O di file di lettura / scrittura.
La primitiva di classificazione a mutua esclusione è il mutex. Per i file mappati in memoria, suggerirei di guardare un mutex mappato in memoria, disponibile utilizzando (ad esempio) pthread_mutex_init ().
Modifica con un solo trucco: quando si utilizzano file mappati, c'è la tentazione di incorporare puntatori ai dati nel file, nel file stesso (si pensi all'elenco collegato memorizzato nel file mappato). Non si desidera farlo, poiché il file potrebbe essere mappato a indirizzi assoluti diversi in momenti diversi o in processi diversi. Utilizzare invece gli offset all'interno del file mappato.