Così stavo leggendo sul modello di memoria che fa parte del prossimo standard C++ 0x. Tuttavia, sono un po 'confuso su alcune delle restrizioni per ciò che il compilatore è autorizzato a fare, in particolare su carichi e negozi speculativi.C++ 0x modello di memoria e carichi/negozi speculativi
Per cominciare, alcune delle cose rilevanti:
Hans Boehm's pages about threads and the memory model in C++0x
Boehm, "Threads Cannot be Implemented as a Library"
Boehm and Adve, "Foundations of the C++ Concurrency Memory Model"
Boehm, "Concurrency memory model compiler consequences", N2338
Ora, l'idea di base è essenzialmente "Consistenza sequenziale per i programmi Data-Race-Free", che sembra essere un compromesso accettabile tra la facilità di programmazione e l'ottimizzazione delle opportunità del compilatore e dell'hardware. Si definisce una corsa di dati se non si ordinano due accessi alla stessa posizione di memoria da parte di fili diversi, almeno uno di essi viene archiviato nella posizione di memoria e almeno uno di essi non è un'azione di sincronizzazione. Implica che tutto l'accesso in lettura/scrittura ai dati condivisi deve avvenire tramite un meccanismo di sincronizzazione, come mutex o operazioni su variabili atomiche (beh, è possibile operare sulle variabili atomiche con l'ordine di memoria rilassato per gli esperti solo, ma il l'impostazione predefinita fornisce coerenza sequenziale).
Alla luce di ciò, sono confuso riguardo le restrizioni sui carichi spuri o speculativi/negozi su ordinarie variabili condivise. Ad esempio, in N2338 abbiamo l'esempio
switch (y) {
case 0: x = 17; w = 1; break;
case 1: x = 17; w = 3; break;
case 2: w = 9; break;
case 3: x = 17; w = 1; break;
case 4: x = 17; w = 3; break;
case 5: x = 17; w = 9; break;
default: x = 17; w = 42; break;
}
cui il compilatore non è permesso di trasformare in
tmp = x; x = 17;
switch (y) {
case 0: w = 1; break;
case 1: w = 3; break;
case 2: x = tmp; w = 9; break;
case 3: w = 1; break;
case 4: w = 3; break;
case 5: w = 9; break;
default: w = 42; break;
}
poiché se y == 2 è una scrittura spuria di x che potrebbe essere un problema se un altro thread stava aggiornando contemporaneamente x. Ma perché questo è un problema? Questa è una gara di dati, che è comunque vietata; in questo caso, il compilatore peggiora semplicemente scrivendo a x due volte, ma anche una singola scrittura sarebbe sufficiente per una corsa di dati, no? Cioè un corretto programma C++ 0x avrebbe bisogno di sincronizzare l'accesso a x, nel qual caso non ci sarebbe più la corsa dei dati, e anche l'archivio spuria non sarebbe un problema?
Sono allo stesso modo confuso circa l'esempio 3.1.3 in N2197 e alcuni degli altri esempi, ma forse una spiegazione per il problema precedente spiegherebbe anche questo.
EDIT: La Risposta:
Il motivo per cui i negozi speculativi sono un problema è che nell'esempio switch sopra, il programmatore potrebbe aver scelto di acquisire in modo condizionale la serratura protegge x solo se y = 2! Quindi il negozio speculativo potrebbe introdurre una corsa di dati che non era presente nel codice originale, e la trasformazione è quindi proibita. Lo stesso argomento vale anche per l'esempio 3.1.3 in N2197.
Forse uno per http://groups.google.com/group/comp.std.c++ –