No 'spe, non facciamo confusione.
Caso 1: apertura/scrittura/chiusura con critical section globale.
L'operazione di apri-scrivi-chiudi avviene sempre insieme e solo un thread alla volta; guardando "da fuori", vedrai sempre un file o vuoto, o con "hello world" o con un qualunque stato intermedio della scrittura (a seconda del buffering).codice:void scrivifile() { EnterCriticalSection(&CSector); FILE *fp; fp=fopen("test.txt","w"); fprintf(fp, "hello world"); fclose(fp); LeaveCriticalSection(&CSector); }
Caso 2, come sopra ma senza critical section: ogni thread apre il suo FILE *, per cui non si "pestano i piedi" a livello di strutture dati lato libreria C, però le scritture arrivano al sistema operativo a caso, per cui nel file potresti avere più o meno qualunque mix delle varie scritture.
Caso 3, FILE * aperto una sola volta all'inizio e tutti fanno fprintf sullo stesso FILE *: dipende da come è implementata la libreria C.
- se la libreria è conforme allo standard C11 (cosa che comunque facevano già da prima la maggior parte delle librerie C che supportavano i thread), allora tutto fila liscio, dato che ogni stream C ha associato un lock che viene acquisito internamente all'inizio della fprintf e rilasciato alla fine. Le singole fprintf avvengono in maniera atomica, e, dato che al sistema operativo arriva tutto dallo stesso stream, non c'è il casino di cui al caso 2.
- in caso contrario (caso classico: si è linkata una versione della CRT pensata per lavorare solo single thread) se non c'è una critical section può succedere di tutto, molto probabilmente un segfault, dato che da più thread si accede alla struttura dati puntata da fp senza sincronizzazione, per cui è facile che rapidamente si venga a trovare in uno stato incoerente.
In ogni caso, il caso dei file non è una buona palestra per parlare di thread safety, dato che è ingarbugliato ulteriormente dal fatto che sono oggetti gestiti internamente dalla CRT (e su cui prima del C11 non c'erano garanzie) e che wrappano internamente una risorsa che può essere condivisa ad un livello più basso (sistema operativo). In genere è meno distraente ragionare su strutture dati condivise tra thread in memoria (vengono a c'entrare meno fattori "distraenti").

Rispondi quotando