Rahat sipariş açıklaması açıklamada yanlış mı?


13

In belgelenmesi std::memory_ordercppreference.com üzerinde rahat sipariş örneği vardır:

Rahat sipariş

Etiketlenen atomik işlemler memory_order_relaxedsenkronizasyon işlemleri değildir; eşzamanlı bellek erişimleri arasında emir vermezler. Sadece atomisite ve modifikasyon sırası tutarlılığını garanti ederler.

Örneğin, başlangıçta x ve y ile sıfır,

// Thread 1:
r1 = y.load(std::memory_order_relaxed); // A
x.store(r1, std::memory_order_relaxed); // B
// Thread 2:
r2 = x.load(std::memory_order_relaxed); // C
y.store(42, std::memory_order_relaxed); // D

Bir rağmen, çünkü r1 == r2 == 42 üretmek için bırakılır daha önce dizilenmiştir Konu 1 içinde B ve C olup önce dizilenmiş iplik 2 içinde D, hiçbir şey önler y modifikasyonu için A daha önce görünmesini D ve B'den x modifikasyon sırasında C'den önce görünür. D'nin y üzerindeki yan etkisi, 1 numaralı iplikteki A yükü tarafından görülebilirken, B üzerindeki x'in yan etkisi, 2 numaralı iplikteki C yükü tarafından görülebilir. Özellikle, D'nin C girişinden önce tamamlanması durumunda bu meydana gelebilir. iş parçacığı 2, derleyici yeniden sıralama nedeniyle veya çalışma zamanında.

"C, iplik 2 içinde D'den önce dizilir" der.

Bulunabilir dizilenmiştir daha önce tanımı göre değerlendirme Düzeni B değerlendirilmesi başlamadan önce bir B önce sekanslanır ise, A daha sonra değerlendirme tamamlanacaktır. C, evre 2 içinde D'den önce sıralandığından, C, D başlamadan önce tamamlanmalıdır, bu nedenle anlık görüntünün son cümlesinin koşul kısmı hiçbir zaman karşılanmaz.


Sorunuz özellikle C ++ 11 ile ilgili mi?
curiousguy

Hayır, c ++ 14,17 için de geçerlidir. Derleyicinin ve CPU'nun C ile D'yi yeniden sıralayabileceğini biliyorum.Ancak yeniden sıralama gerçekleşirse, C başlamadan C tamamlanamaz. Bu yüzden "A dizisi-1 evre B önce ve C evre D 2 evre D önce dizildi" cümlesinde bir terminoloji-yanlış kullanım olduğunu düşünüyorum. "Kodda A, 1. iplik içinde B ÖNCE yerleştirilir ve C, 2. iplik içinde D ÖNCE yerleştirilir" demek daha doğru olur. Bu sorunun amacı bu düşünceyi doğrulamak içindir
Abigaile

Hiçbir şey "yeniden sıralama" terimiyle tanımlanmaz.
curiousguy

Yanıtlar:


12

Bence cppreference doğru. Bence bu "as-if" kuralı [intro.execution] / 1 . Derleyiciler yalnızca kodunuz tarafından açıklanan programın gözlemlenebilir davranışını yeniden oluşturmakla yükümlüdür. Önceden sıralı bir ilişki, yalnızca bu değerlendirmelerin yapıldığı iş parçacığı perspektifinden değerlendirmeler arasında kurulur [intro.execution] / 15 . Bu, birbiri ardına sıralanan iki değerlendirme, bir iş parçacığında bir yerde göründüğünde, o iş parçacığında çalışan kodun , ilk değerlendirme ne yaparsa yapsın, ikinci değerlendirmenin ne yaptığını etkilermiş gibi davranması gerektiği anlamına gelir. Örneğin

int x = 0;
x = 42;
std::cout << x;

gerekir Ancak 42. baskı, derleyici aslında bir nesne haline değeri 42 saklamak zorunda değildir xyazdırmak için bu nesneden değer geri okumadan önce. Ayrıca, depolanacak son değerin x42 olduğunu hatırlayabilir ve daha sonra 42 değerinin gerçek bir deposunu yapmadan önce 42 değerini doğrudan yazdırabilirsiniz x. Aslında, xbir yerel değişkense, bu değişkenin herhangi bir noktada en son hangi değere atandığını da izleyebilir ve asla bir nesne bile oluşturmaz ya da gerçekte 42 değerini saklamaz. İş parçacığının farkı anlatması mümkün değildir. Davranış hep olacak sanki bir değişken olduğunu ve sanki değeri 42 aslında bir nesne saklandı x önceo nesneden yükleniyor. Ancak bu, üretilen makine kodunun herhangi bir yerde herhangi bir şeyi depolaması ve yüklemesi gerektiği anlamına gelmez. Gerekli olan tek şey, üretilen makine kodunun gözlemlenebilir davranışının, tüm bu şeyler gerçekten gerçekleşecek olsaydı, davranışın ne olacağından ayırt edilemez olmasıdır.

Bakarsak

r2 = x.load(std::memory_order_relaxed); // C
y.store(42, std::memory_order_relaxed); // D

o zaman evet, C, D'den önce sıralanır. Ancak bu iplikten ayrı olarak bakıldığında, C'nin D'nin sonucunu etkilemediği hiçbir şey ve D'nin yaptığı hiçbir şey C'nin sonucunu değiştirmez. başka bir iş parçacığında meydana gelen bir şeyin dolaylı bir sonucu olarak. Ancak belirterek tarafından std::memory_order_relaxed, sen açıkça belirtilmediğiyükün ve deponun başka bir iplik tarafından gözlemlenme sırası önemsizdir. Başka hiçbir iş parçacığı yükü gözlemleyemediğinden ve belirli bir sırada depolayamadığından, C ve D'nin birbirini tutarlı bir şekilde etkilemesini sağlamak için başka bir iş parçacığının yapabileceği hiçbir şey yoktur. Bu nedenle, yükün ve deponun gerçekte gerçekleştirilme sırası önemsizdir. Böylece, derleyici onları yeniden sıralamakta serbesttir. Ve bu örneğin altındaki açıklamada belirtildiği gibi, D'den gelen mağaza C'den gelen yükten önce gerçekleştirilirse, r1 == r2 == 42 gerçekten gelebilir…


Bu yüzden esasen standart, C'nin D'den önce olması gerektiğini belirtir , ancak derleyici C veya D'nin bir sonraki gerçekleşip gerçekleşmediğinin kanıtlanamayacağına ve as-if kuralı nedeniyle bunları yine de yeniden sıraladığına inanıyor mu?
Ocak'ta

4
@ Fureeish No. C, gerçekleştikleri konuya göre D'den önce gerçekleşmelidir. Başka bir bağlamdan gözlem yapmak bu görüşle tutarsız olabilir.
Deduplicator

Hiçbir "kural gibi" yok
curiousguy


1
@curiousguy standart yapar dipnotta 's hükümler "olarak eğer kural" etiket: Biri olarak eğer "kuralı‘’Bu hüküm bazen denir" intro.execution
Caleth

1

Bazen, bir eylemin, bu dizilerdeki eylemlerin birbirlerine göre göreceli bir sırasını ima etmeden, diğer iki eylem dizisine göre sıralanması mümkündür.

Örneğin, şu üç olaya sahip olduğunu varsayalım:

  • 1'den p1'e kadar depola
  • p2'yi sıcaklığa yükleyin
  • mağaza 2'den p3'e

ve p2'nin okunması bağımsız olarak p1'in yazılmasından sonra ve p3'ün yazılmasından önce sıralanır, ancak hem p1 hem de p3'ün ayrıldığı belirli bir sıralama yoktur. P2 ile ne yapıldığına bağlı olarak, bir derleyicinin p1'i p3'ü ertelemesi ve yine de p2 ile gerekli semantiğe ulaşması pratik olmayabilir. Bununla birlikte, derleyicinin yukarıdaki kodun daha büyük bir dizinin parçası olduğunu bildiğini varsayalım:

  • 1'den p2'ye kadar [p2 yükünden önce dizilenmiş]
  • [yukarıdakileri yapın]
  • mağaza 3'ü p1'e [diğer mağazadan sonra p1'e dizilir]

Bu durumda, yukarıdaki koddan sonra mağazayı p1 olarak yeniden sıralayabildiğini ve aşağıdaki mağaza ile birleştirebileceğini belirleyebilir, böylece önce p1 yazmadan p3 yazan kodla sonuçlanabilir:

  • temp 1 olarak ayarla
  • mağaza sıcaklığı p2
  • mağaza 2'den p3'e
  • 3'ten p1'e kadar depola

Veri bağımlılıklarının, sıralama ilişkilerinin belirli bölümlerinin geçişli davranmasına neden olacağı görünse de, bir derleyici, görünür veri bağımlılıklarının olmadığı durumları belirleyebilir ve bu nedenle beklendiği geçişsel etkileri olmayacaktır.


1

İki ifade varsa, derleyici kodu sıralı olarak oluşturur, böylece ilk kod ikinci kodun önüne yerleştirilir. Ancak cpus dahili olarak boru hatlarına sahiptir ve montaj işlemlerini paralel olarak yürütebilir. İfade C bir yük talimatıdır. Bellek getirilirken, boru hattı sonraki birkaç talimatı işleyecek ve yük komutuna bağlı olmadıkları takdirde, C bitmeden önce yürütülebilirler (örneğin, D için veriler önbellekte, ana bellekte C).

Kullanıcının iki ifadenin ardışık olarak yürütülmesine gerçekten ihtiyacı varsa, daha katı bellek sıralama işlemleri kullanılabilir. Genel olarak, program mantıksal olarak doğru olduğu sürece kullanıcılar umursamazlar.


-7

Düşündüğünüz her şey eşit derecede geçerli. Standart, neyin ardışık olarak yürütüldüğünü, neyin çalışmadığını ve nasıl karıştırılabileceğini söylemez .

Birden fazla doktora layık bir çalışma olan bu karmaşa üzerine tutarlı bir anlambilim oluşturmak size ve her bir programcıya bağlıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.