Dopo aver guardato un sacco di altre domande e le loro risposte , ho l'impressione che non c'è accordo diffusa su ciò che la parola chiave "volatile" in C significa esattamente.
Anche lo standard stesso non sembra essere abbastanza chiaro da consentire a tutti di concordare sul significato .
Tra gli altri problemi:
- Sembra fornire diverse garanzie a seconda dell'hardware e in base al compilatore.
- Colpisce le ottimizzazioni del compilatore ma non le ottimizzazioni hardware, quindi su un processore avanzato che esegue le proprie ottimizzazioni di runtime, non è nemmeno chiaro se il compilatore può impedire qualsiasi ottimizzazione che si desidera impedire. (Alcuni compilatori generano istruzioni per impedire alcune ottimizzazioni hardware su alcuni sistemi, ma questo non sembra essere standardizzato in alcun modo.)
Per riassumere il problema, sembra (dopo aver letto molto) che "volatile" garantisce qualcosa del tipo: Il valore verrà letto / scritto non solo da / verso un registro, ma almeno nella cache L1 del core, nello stesso ordine in cui le letture / scritture appaiono nel codice. Ma questo sembra inutile, dal momento che leggere / scrivere da / verso un registro è già sufficiente all'interno dello stesso thread, mentre il coordinamento con la cache L1 non garantisce nulla di più riguardo al coordinamento con altri thread. Non riesco a immaginare quando potrebbe mai essere importante sincronizzare solo con la cache L1.
USO 1
L'unico uso ampiamente concordato di volatile sembra essere per sistemi vecchi o incorporati in cui determinate posizioni di memoria sono mappate hardware su funzioni I / O, come un po 'nella memoria che controlla (direttamente, nell'hardware) una luce o un po 'in memoria che indica se un tasto della tastiera è inattivo o meno (perché è collegato dall'hardware direttamente al tasto).
Sembra che "use 1" non si verifichi nel codice portatile i cui target includono sistemi multi-core.
USE 2
Non troppo diverso da "use 1" è la memoria che può essere letta o scritta in qualsiasi momento da un gestore di interrupt (che potrebbe controllare una luce o memorizzare informazioni da un tasto). Ma già per questo abbiamo il problema che, a seconda del sistema, il gestore di interrupt potrebbe funzionare su un core diverso con la propria cache di memoria e "volatile" non garantisce la coerenza della cache su tutti i sistemi.
Quindi "usa 2" sembra essere al di là di ciò che "volatile" può offrire.
USO 3
L'unico altro uso indiscusso che vedo è prevenire un'errata ottimizzazione degli accessi tramite variabili diverse che puntano alla stessa memoria che il compilatore non capisce è la stessa memoria. Ma questo è probabilmente solo indiscusso perché le persone non ne parlano - ne ho visto solo una menzione. E pensavo che lo standard C avesse già riconosciuto che puntatori "diversi" (come argomenti diversi a una funzione) potessero puntare allo stesso oggetto o elementi vicini, e già specificato che il compilatore doveva produrre codice che funzionasse anche in questi casi. Tuttavia, non sono riuscito a trovare rapidamente questo argomento nell'ultimo standard (500 pagine!).
Quindi "usa 3" forse non esiste affatto?
Da qui la mia domanda:
"Volatile" garantisce qualcosa nel codice C portatile per sistemi multi-core?
EDIT - aggiorna
Dopo aver sfogliato lo standard più recente , sembra che la risposta sia almeno un sì molto limitato:
1. Lo standard specifica ripetutamente un trattamento speciale per il tipo specifico "volatile sig_atomic_t". Tuttavia, lo standard afferma anche che l'uso della funzione del segnale in un programma multi-thread comporta un comportamento indefinito. Quindi questo caso d'uso sembra limitato alla comunicazione tra un programma a thread singolo e il suo gestore di segnale.
2. Lo standard specifica inoltre un chiaro significato di "volatile" in relazione a setjmp / longjmp. (Esempio di codice in cui è importante è riportato in altre domande e risposte .)
Quindi la domanda più precisa diventa:
"volatile" garantisce qualcosa nel codice C portatile per sistemi multi-core, tranne (1) che consente a un programma a thread singolo di ricevere informazioni dal suo gestore di segnale, o (2) che consente setjmp codice per vedere le variabili modificate tra setjmp e longjmp?
Questa è ancora una domanda sì / no.
Se "sì", sarebbe bello se si potesse mostrare un esempio di codice portatile privo di bug che diventa difettoso se si omette "volatile". Se "no", suppongo che un compilatore sia libero di ignorare "volatile" al di fuori di questi due casi molto specifici, per target multi-core.
volatile
particolare, che credo sia necessaria.
volatile
quello di informare il programma che potrebbe cambiare in modo asincrono.