2013-05-06 12 views
5

Sto chiedendo specificamente nel senso del modello di memoria. http://en.cppreference.com/w/cpp/atomic/memory_orderLe istruzioni condizionali C++ portano una dipendenza dall'espressione della condizione all'istruzione?

Mi sto chiedendo perché voglio sapere se posso usare un std::memory_order_consume nel qui sotto:

mLocalMemPtr1 e 2 e mAtomicMemPtr sono puntatori in un buffer condiviso.

In un thread produttore che sto facendo:

for (int x = 0; x < 10; ++x) 
{ 
    ++mLocalMemPtr1 
    *mLocalMemPtr1 = x;  // <========= A 
    mAtomicMemPtr.store(mLocalMemPtr1, std::memory_order_release); 
} 

E nel consumatore:

tempMemPtr = mAtomicMemPtr.load(std::memory_order_consume); 
while (tempMemPtr != mLocalMemPtr2) 
{ 
    ++mLocalMemPtr2; 
    int test = *mLocalMemPtr2; // <======== B 
    doSomeLongRunningThing(test); 
    tempMemPtr = mAtomicMemPtr.load(std::memory_order_consume); 
} 

così fa la catena di dipendenza go tempMemPtr -> mLocalMemPtr2 -> prova -> doSomeLongRunningThing?

Sono particolarmente preoccupato che B possa essere eseguito prima dello A. So che posso usare un std::memory_order_acquire, ma posso usare consumare (che è più leggero) se l'istruzione condizionale causa una dipendenza dell'ordine di memoria.

risposta

0

Credo che con l'ordinamento consume, il compilatore potrebbe effettivamente effettuare una copia dell'intero mSharedBuffer in anticipo. È necessaria la semantica acquire per invalidare le copie precedentemente memorizzate nella cache di variabili diverse da mAtomicMemLocPtr .

2

CppReference:

uscita-consumo ordinare

Se un negozio atomica in filo A viene etichettato std :: memory_order_release e un carico atomica in filo B dal medesimo variabile viene etichettato std :: memory_order_consume , tutte le scritture di memoria (atomiche non atomiche e rilassate) che sono dependance-ordinate-prima dello archivio atomico dal punto di vista del thread A, diventano visibili effetti collaterali nel thread B, ovvero, una volta che il carico atomico è completato, il thread B è garantito per vedere tutto ciò che il thread A ha scritto in memoria se è porta una dipendenza dati nel carico atomico.

1.10.10:

Una valutazione A è dipendenza-ordinato prima di una valutazione B se

- A esegue un'operazione di rilascio su un oggetto M atomico, e, in un altro thread, B esegue un'operazione di consumare su M e legge un valore scritto da qualsiasi effetto collaterale nella sequenza di rilascio guidato da un (...)

1.10.9:

Una valutazione A trasporta una dipendenza di una valutazione B se - il valore di A è utilizzato come operando di B, salvo:

- B è un'invocazione di qualsiasi specializzazione std :: kill_dependency (29.3), o

- A è l'operando sinistro dell'operatore incorporato AND logico (& &, vedi 5.14) oppure OR logico (||, vedi 5.15), o

- A è sinistra operando di un operatore condizionale (?:, vedere 5.16) o

- A è l'operando di sinistra dell'operatore di virgola (,) incorporato (5.18); (...)

Sulla base di questi fatti, dico che mLocalMemPtr2 deve essere sincronizzato. Tuttavia, c'è ancora una questione sull'ordine di valutazione.

if (atomic.load(std::consume) < x) 

Quello che viene valutato per primo non è specificato. C'è nessuna garanzia (come non riuscivo a trovare nello standard) che il compilatore eseguirà prima l'operazione di consumo, aggiornare il buffer condiviso e quindi caricare atomice quindix.

Non avendo trovato una prova che operandi vengono valutati in modo "desiderato", io dico che senza decomposizione esplicito del carico atomica mLocalMemPtr2 non funzionerà e CPU potrebbe leggere il valore stantio della memoria puntato da mLocalMemPtr2. memory_order_acquire non cambierebbe molto qui, dato che mLocalMemPtr2 ha una dipendenza dai dati.

Problemi correlati