2017-10-07 5 views
0

Excuses si cela a déjà été répondu, ou si quelque chose me manque.Les opérations atomiques imbriquées sont-elles garanties atomiques?

J'essaie de comprendre à quel point les garanties de l'atomicité vont de std::atomic. Par exemple, si nous avons

std::atomic<int> a(0); 
a.store(1); 

l'opération de stockage est atomique. Cependant, ce qui se passe si nous avons imbriqué des opérations atomiques, comme ceci:

std::atomic<int> a(0); 
std::atomic<int> b(1); 
a.store(++b); 

Ma compréhension est que ++b est atomique, et est donc store(). Ai-je raison de supposer que cela est garanti de stocker 2 atomiquement dans a?

Plus important encore, si a et b sont partagés entre les fils T1 et T2, est-il garanti que a.store(++b); effectué par les deux fils va stocker la valeur incrémentée de b (comme on le voit par les fils respectifs) dans a atomiquement dans chaque fil? En d'autres termes, peut enfiler T2 « bout à bout dans » et incrémenter b une fois de plus aprèsT1 a déjà incrémentée une fois, mais avant le résultat est stocké dans a par T1?

+0

En supposant 'B' est partagé entre du fil, incrémentation de 'B' peut se produire avant 'a.store (++ b);'. donc la valeur de 'a' n'est pas garantie d'être' 2'. – Jarod42

Répondre

2

L'incrément est atomique et le stockage est atomique, mais les deux opérations ne le sont pas. Il est possible que le premier thread incrémente b, soit suspendu, puis un autre thread incrémente b et stocke cette valeur dans a, puis le premier thread reprend et stocke sa valeur (maintenant périmée) de b en a.

+0

'b' n'évalue qu'une seule fois. ainsi, à partir de l'exemple OP, un «2» serait conservé même si maintenant «b» est «3». – Jarod42

+0

Merci, je m'en doutais autant, mais c'est bien de l'avoir confirmé. Il n'y a donc pas d'atomicité "imbriquée". – cantordust

1

L'atomicité ne comprend pas.

En supposant que personne d'autre écrit jamais a et b et un autre thread essaie de lire à la fois après qu'ils existent, et ils lisent b alors a, lit possible sont exactement:

{b,a} 
{1,0} 
{2,0} 
{2,2} 

s'ils lisent a puis b:

{a,b} 
{0,1} 
{0,2} 
{2,2} 

qui dans ce cas est le même que b puis a.

+0

Donc la seule garantie est que le thread de lecture ne peut pas obtenir '{a, b}' '{1,2}' En d'autres termes, 'b' ne sera pas stocké dans' a' avant qu'il ne soit incrémenté au moins une fois que. Est-ce exact? – cantordust

1
a.store(++b); 

est équivalent à

int temp = ++b; 
/* other threads can modify `b` but its value has been save in temp ... */ 
a.store(temp); 
+0

Eh bien, il y a un argument selon lequel l'opérateur de pré-incrémentation ne crée pas de valeur temporaire. – cantordust

+0

Je veux dire que 'operator ++' renvoie un 'int' pas un' std :: atomic ', donc la modification future de' b' n'affecte pas la valeur stockée dans 'a'. – Jarod42