C ++ std :: memory_order_relaxed kafa karışıklığı

Oct 12 2020

GCC Wiki'den C ++ bellek engelleri (ve harika) hakkındaki bu makaleyi okuyordum .
Bu noktaya gelene kadar oldukça basitti:

Bunun tersi yaklaşım std :: memory_order_relaxed'dir. Bu model, önceden gerçekleşen kısıtlamaları kaldırarak çok daha az senkronizasyon sağlar. Bu tür atomik işlemler, ölü depo kaldırma ve ortaklaştırma gibi çeşitli optimizasyonlara da sahip olabilir. Yani önceki örnekte:

-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 */

İş parçacığının sistem genelinde senkronize edilmesine gerek olmadığından, bu örnekteki iddia aslında BAŞARISIZ olabilir.

Tamam, bu da basit, devam edelim ..

-Thread 1-
x.store (1, memory_order_relaxed)
x.store (2, memory_order_relaxed)

-Thread 2-
y = x.load (memory_order_relaxed)
z = x.load (memory_order_relaxed)
assert (y <= z)

İddia başarısız olamaz. 2'nin deposu, iplik 2 tarafından görüldüğünde, artık değeri 1 göremez. Bu, bir değişkenin gevşemiş yüklerinin, takma ada sahip olabilecek farklı bir referansın gevşemiş yükleri arasında birleştirilmesini önler.

Bu benim kafamı karıştırdı, neden y değeri 2'yi yükleyemiyor ve z değeri 1'i yükleyemiyor (ve onaylamanın başarısız olmasına neden oluyor), çünkü sıralama iş parçacığı 1'de senkronize değil?

Yanıtlar

4 NicolBolas Oct 12 2020 at 12:12

Gevşetilmiş sıralama, atomik gevşemeyle değiştirilene göre sıralama değil, diğer bellek erişimleri ile ilgili işlemlerin sırasına bağlıdır. İlk durumunuzda, 10'da görebiliyor xolmanız, değeriyle ilgili hiçbir şey ifade etmez y. Ve tam tersi.

Ama ikinci durumunuz farklı çünkü aynı atomik nesneyi etkiliyor.

[intro.races] / 10 , bir iş parçacığı içinde, bir işlem diğerinden önce sıralanırsa, o işlemin diğerinden "önce gerçekleştiğini" söyler. Ve [intro.races] / 14-17 atomikle ilgili aşağıdaki davranışı özetlemektedir :

Önceki dört tutarlılık gereksinimi, her iki işlem de gevşetilmiş yükler olsa bile, derleyicinin atomik işlemlerin tek bir nesneye yeniden sıralanmasına etkili bir şekilde izin vermez.

Ve burada sahip olduğun şey bu. Tüm değişiklikler aynı nesneye oluyor, bu yüzden bir sırayla gerçekleşmeleri gerekiyor . Bu sıra tam olarak belirlenemese bile, sıra, kodun "önce gerçekleşir" ilişkilerine uymalıdır.

İş parçacığı 1'in iki işlemi bir "önce gerçekleşir" ilişkisine göre sıralanır. Ve Thread 2'nin operasyonları "önce olur" ilişkisine göre sıralanır.

Hepsi aynı atom nesnesine etki yettiğinden , eğer 2 değerini alırsa, o zaman "sonra" x2'ye ayarlanmış olmalıdır. Bu nedenle, erişim sırası x"x = 1, x = 2 olmalı, x "okuyun. Ve son okuma x, ilk okumadan sonra gerçekleştiğinden x, aldığı değer 1 olamaz.