2010-03-18 4 views
30

Gli operatori di "modifica" come +=, |=, &= ecc. Sono atomici?Are + =, | =, & = etc atomic?

so ++ è atomica (se si esegue x++; in due diversi thread "simultaneamente", si finisce sempre con x aumentato di 2, al contrario di x=x+1 con l'ottimizzazione spento.)

Quello che mi chiedo è se variable |= constant e le mi piace sono thread-safe o devo proteggerli con un mutex?

(... o è CPU-dipendente? In questo caso, come è su ARM?)

+1

Quale ARM? Architecture v6 (ARM10) e versioni successive possono fornire operazioni atomiche, se il compilatore lo supporta o se si rotola il proprio assembly. Le architetture precedenti non possono. –

+0

gcc ha incorporato operazioni atomiche: http://gcc.gnu.org/onlinedocs/gcc-4.4.3/gcc/Atomic-Builtins.html#Atomic-Builtins; si prega di notare: "Non tutte le operazioni sono supportate da tutti i processori di destinazione" – Christoph

+0

c'è l'API di Windows per l'accesso variabile interbloccato: http://msdn.microsoft.com/en-us/library/ms684122%28v=VS.85%29.aspx –

risposta

72

Ti sbagli. Non vi è alcuna garanzia che ++ sia atomico e che non ci sia né per gli operatori di assegnazione dei composti né per qualsiasi operazione C++.

+3

Ciò significa che questo è specifico della CPU. Nelle architetture single-core che consentono 'inc [indirizzo]', questo è decisamente atomico. –

+1

Almeno fino a C++ 0x: "Questa clausola descrive i componenti per l'accesso atomico a grana fine, che viene fornito tramite operazioni su oggetti atomici." [29.1/1 nella bozza n3035]. –

+24

@SF No, non lo è. È specifico del compilatore.Solo perché un'architettura della CPU ha un'istruzione non significa che il compilatore la userà nel modo in cui pensi che dovrebbe, se effettivamente la usa affatto. –

6

Affinché la modifica del valore sia visibile attraverso i core, a + = (per esempio) dovrebbe caricare il valore, aggiungere l'incremento e quindi memorizzarlo. Ciò significa che l'operazione non sarà atomica.

Per garantire l'atomicità è necessario inserire un blocco appropriato per l'operazione.

2

++ potrebbe essere atomico sul tuo compilatore/piattaforma, ma nelle specifiche C++ non è definito come atomico.

Se si desidera assicurarsi di modificare un valore in modo atomico, è necessario utilizzare i metodi appropriati, come Interblocco * su Windows.

Uguale a tutte le altre routine. Se si desidera eseguire operazioni atomiche, è necessario utilizzare le chiamate appropriate, non quelle standard.

2

Nessun operatore in C o C++ è garantito per essere atomico. Potrebbero essere sulla tua piattaforma, ma non lo saprai per certo. Tipicamente, l'unica operazione che è atomica è l'istruzione Test e Set, che è solitamente disponibile sulla maggior parte delle CPU moderne in qualche modo come base per l'implementazione di semafori.

9

x++ viene spesso implementato in 3 istruzioni: leggere X in un registro, incrementarlo e riportarlo in memoria.

Il thread può essere escluso tra uno di questi.

+1

Su alcuni processori, anche singole istruzioni possono essere non atomiche. –

0

Vale la pena ricordare che questi operatori possono essere sovraccaricati, quindi non ci può essere alcuna garanzia generale che siano atomici per tutte le classi.

+1

Non possono essere sovraccaricati per i numeri interi, che penso sia la domanda. –

+0

D'accordo, ma non lo dice, motivo per cui ho pensato che fosse degno di nota. – Oddthinking

0

Anche se ++ è un'operazione atomica, che non implica che due thread che fanno ++x comporteranno in x esattamente due in alto. Devi sincronizzare i thread in qualche modo, altrimenti non vedranno necessariamente i cambiamenti dell'altro.

0

devi proteggere la variabile, con un mutex per esempio

2

E 'sia del compilatore e CPU dipendente. Alcuni set di istruzioni forniscono istruzioni atomiche per questi (su dispositivi di dimensioni macchina).

Tuttavia, non è garantito che il compilatore utilizzerà tali istruzioni e non ottimizzerà il codice in modo non sicuro. È necessario scrivere la routine in assembly o utilizzare una tecnica specifica del compilatore (come instrinsics) che fornisce atomicità (o utilizzare una libreria che utilizza una di queste tecniche).


particolare su ARM: L'ORR/ADD/E istruzioni prende due operandi e inserire il risultato in un registro. Entrambi gli operandi possono essere lo stesso registro del registro dei risultati, quindi possono essere utilizzati come atomico | =, + =, & =.

Ovviamente, il risultato viene inserito in un registro e il primo operando deve anche provenire da un registro, quindi è necessario accertarsi che i carichi del registro siano eseguiti in modo atomico.

1

Un duplicare è stato diretto qui, e questo ha bisogno di un aggiornamento. Il “nuovo” linguaggio C11 consente un attributo atomica che ammette che:

_Atomic int a; 
... 
a += 3 

può essere compilato in un (atomico) ciclo illimitata. Grazie per la gente di standard di regalo, davvero vorrei che tu non avessi.

1: in alcune architetture, le operazioni atomiche sono possibili solo su memoria che supporta determinati protocolli di accesso. ARMv7, MIPS per esempio girare la sequenza in:

do { 
    x = LoadLinked(a) + 3; 
} while !StoreConditional(x, &a); 

ma LoadLinked/StoreConditional è definito per alcuni tipi di memoria/cache. Godetevi il debug di questo.

2: correlati è falso condivisione che è un artefatto di LoadLinked, StoreConditional operando sullo linee di cache non sottoblocchi (ad esempio 32, 64, 256 byte.). Quindi: _Atomic int a [4]; potrebbe richiedere 4 * dimensioni della linea cache (quindi 1024 byte) per consentire operazioni atomiche simultanee su un [n] e un [n + 1], perché 4 cpu potrebbero essere preoccupanti per aggiornare un [0..3], ma mai riuscendo.

Speriamo che lo standard successivo riconosca l'errore intrinseco della decorazione degli attributi e ripristini c89 come standard C corretto.