Hakkında birkaç makale, görüşme ve yığın akışı ile ilgili soruları dinledim ve okudum ve std::atomic
bunu iyi anladığımdan emin olmak istiyorum. Önbellek satırıyla hala kafam karıştığından, MESI (veya türetilmiş) önbellek tutarlılık protokollerinde, mağaza arabelleklerinde, geçersiz sıralarda vb. Olası gecikmeler nedeniyle görünürlük yazıyor.
X86'nın daha güçlü bir bellek modeli olduğunu okudum ve önbellek geçersiz kılma gecikirse x86 başlatılan işlemleri geri alabilir. Ama şimdi sadece platformdan bağımsız olarak bir C ++ programcısı olarak neyi varsaymam gerektiğiyle ilgileniyorum.
[T1: thread1 T2: thread2 V1: paylaşılan atomik değişken]
Anladım ki std :: atomic bunu garanti ediyor,
(1) Bir değişken üzerinde veri yarışları meydana gelmez (önbellek hattına özel erişim sayesinde).
(2) Hangi bellek_sayısını kullandığımıza bağlı olarak, (engellerle) sıralı tutarlılığın (bir engelden önce, bir engelden veya her ikisinden sonra) olmasını garanti eder.
(3) T1 üzerine bir atomik yazımdan (V1) sonra, T2'deki bir atomik RMW (V1) tutarlı olacaktır (önbellek satırı T1'deki yazılı değerle güncellenmiş olacaktır).
Ancak önbellek tutarlılık primerinden bahsedildiği gibi,
Tüm bunların anlamı, varsayılan olarak yüklerin eski verileri getirebilmesidir (karşılık gelen bir geçersiz kılma isteği geçersiz kılma kuyruğunda oturuyorsa)
Peki, aşağıdakiler doğru mu?
(4) std::atomic
, T2'nin T1 üzerine bir atomik yazıdan (V) sonra bir atomik okuma (V) üzerinde 'bayat' bir değer okumadığını garanti ETMEZ.
(4) doğruysa sorular: T1'deki atomik yazma gecikme ne olursa olsun önbellek satırını geçersiz kılarsa, T2 bir atomik RMW işlemi yaparken ancak bir atomik okumada geçersiz kılmanın etkili olmasını neden bekler?
(4) yanlışsa sorular: bir iş parçacığı yürütmede "bayat" değerini ve "görünür" ne zaman okuyabilir?
Cevaplarını çok takdir ediyorum
Güncelleme 1
Görünüşe göre (3) 'de yanılmışım. İlk V1 = 0 için aşağıdaki serpiştirmeyi düşünün:
T1: W(1)
T2: R(0) M(++) W(1)
Bu durumda T2'nin RMW'sinin tamamen W (1) 'den sonra gerçekleşeceği garanti edilmesine rağmen, yine de' eski 'bir değer okuyabilir (yanılmışım). Buna göre, atomik tam önbellek tutarlılığını garanti etmez, sadece sıralı tutarlılığı garanti eder.
Güncelleme 2
(5) Şimdi bu örneği düşünün (x = y = 0 ve atomik):
T1: x = 1;
T2: y = 1;
T3: if (x==1 && y==0) print("msg");
konuştuklarımıza göre, ekranda görüntülenen "msg" yi görmek bize T2'den sonra T2'nin yürütülmesinin ötesinde bilgi vermeyecektir. Yani aşağıdaki infazlardan herhangi biri olmuş olabilir:
- T1 <T3 <T2
- T1 <T2 <T3 (burada T3 x = 1 görür ancak y = 1 görmez)
bu doğru mu?
(6) Bir iş parçacığı her zaman 'eski' değerleri okuyabiliyorsa, tipik "yayınla" senaryosunu alırsak ancak bazı verilerin hazır olduğunu belirtmek yerine tam tersini yaparız (verileri silin)?
T1: delete gameObjectPtr; is_enabled.store(false, std::memory_order_release);
T2: while (is_enabled.load(std::memory_order_acquire)) gameObjectPtr->doSomething();
burada T2, is_enabled'ın yanlış olduğunu görünceye kadar silinmiş bir ptr kullanır.
(7) Ayrıca, ipliklerin 'bayat' değerleri okuyabileceği gerçeği, muteksin sadece bir kilitsiz atom hakkı ile uygulanamayacağı anlamına mı geliyor? Dişler arasında bir senkron mekanizması gerektirir. Kilitlenebilir bir atomik mi gerektirir?