O código a seguir vem do GCC Wiki .
// -Thread 1- y.store (20, memory_order_relaxed) x.store (10, memory_order_relaxed) // -Thread 2- if (x.load (memory_order_relaxed) == 10) { assert (y.load(memory_order_relaxed) == 20) /* assert A */ y.store (10, memory_order_relaxed) } // -Thread 3- if (y.load (memory_order_relaxed) == 10) assert (x.load(memory_order_relaxed) == 10) /* assert B */
Como os threads não precisam ser sincronizados no sistema, qualquer uma das asserções neste exemplo pode realmente FALHAR .
Eu consigo entender por que assert A pode falhar. Mas como assert B também pode falhar?
Isso y.load() == 10
implica o fim do tópico 2, então x.load() == 10
?
Pode ser possível somente em uma máquina que não seja multi-copy-atomic (como POWER), onde a reordenação IRIW é possível. ( Duas gravações atômicas em locais diferentes em threads diferentes sempre serão vistas na mesma ordem por outras threads? ).
Então o T2 vê
x == 10
antes de ser visível globalmente e armazenay=10
.O T3 pode então ler o armazenamento do T2
y
antes que ox=10
armazenamento fique visível para ele. (Reordenação do StoreStore do núcleo físico executando T1 e T2 para o núcleo físico executando T3).Isso pode ser possível em hardware POWER ou NVidia ARMv7 real se T1 e T2 forem executados em núcleos lógicos diferentes do mesmo núcleo físico, e T3 for executado em um núcleo físico separado.
Em termos de modelos de memória C ou C++, o assert pode falhar porque nada garante visibilidade. O fato de uma thread ter visto um valor não implica que todas as threads podem ver esse valor.
Pode haver outros mecanismos mais simples também, mas o
assert
in T2 significa quey.store (10, relaxed)
isso não acontece se essa afirmação falhar, então não é tão simples quanto apenasx.load
executar beforey.load
.