Std :: atomic <T> :: is_lock_free () neden constexpr kadar statik değil?


9

Birisi bana std :: atomic :: is_lock_free () 'nin constexpr kadar statik olup olmadığını söyleyebilir mi? Statik ve / veya constexpr olmayan bir şekilde olması benim için bir anlam ifade etmiyor.


3
Farkında mısınız is_always_lock_free?
Mike van Dyke

3
Oraya "hizalama" atacağım.
Max Langhof

@MaxLanghof Tüm örneklerin aynı şekilde hizalanmayacağını mı kastediyorsunuz?
curiousguy

1
Mike, hayır, farkında değildim, ama bu ipucu için teşekkürler; Bu benim için gerçekten yardımcı oldu. Ama kendime neden is_lock_free () ve is_always_lock_free arasında bir karar olduğunu soruyorum. Bu, başkalarının önerdiği gibi, hizalanmamış atomlar nedeniyle olamaz, çünkü dil, tanımlanmamış davranışları zaten tanımlanmamış davranışa sahip olmak için tanımlar.
Bonita Montero

Yanıtlar:


10

Cppreference'de açıklandığı gibi :

Std :: atomic_flag dışındaki tüm atomik tipler, kilitsiz atomik CPU talimatları kullanmak yerine muteksler veya diğer kilitleme işlemleri kullanılarak uygulanabilir. Atomik tiplerin bazen kilitsiz olmasına izin verilir, örneğin belirli bir mimaride yalnızca hizalanmış bellek erişimleri doğal olarak atomikse, aynı tipteki yanlış hizalanmış nesnelerin kilitleri kullanması gerekir.

C ++ standardı, kilitsiz atomik işlemlerin de adressiz olmasını, yani paylaşılan bellek kullanan işlemler arasındaki iletişim için uygun olmasını önerir (ancak gerektirmez).

Birden fazla kişi tarafından belirtildiği gibi std::is_always_lock_free, gerçekten aradığınız şey olabilir.


Düzenleme: Açıklığa kavuşturmak için, C ++ nesne türleri, örneklerinin adreslerini yalnızca iki ( [basic.align]) kuvvetinin katları ile sınırlayan bir hizalama değerine sahiptir . Bu hizalama değerleri temel türler için uygulama tanımlıdır ve türün boyutuna eşit olması gerekmez. Ayrıca donanımın gerçekten destekleyebileceğinden daha katı olabilirler.

Örneğin, x86 (çoğunlukla) hizalanmamış erişimleri destekler. Bununla birlikte, alignof(double) == sizeof(double) == 8hizalanmamış erişimlerin bir dizi dezavantajı (hız, önbellekleme, atomisite ...) olduğu için x86 için olan çoğu derleyiciyi bulacaksınız . Ama örneğin #pragma pack(1) struct X { char a; double b; };veya alignas(1) double x;"hizalanmamış" doublelara sahip olmanızı sağlar . Dolayısıyla cppreference, "hizalanmış bellek erişimleri" hakkında konuştuğunda, muhtemelen, C ++ türünü hizalama gereksinimlerine (UB olacaktır) aykırı bir şekilde kullanmadan, donanım türünün doğal hizalaması açısından bunu yapar.

Daha fazla bilgi: Başarılı hizalanmamış erişimlerin x86 üzerindeki gerçek etkisi nedir?

Lütfen aşağıdaki @Peter Cordes'ın sunduğu yorumlara da göz atın !


1
32 bit x86, ABI'leri nerede bulacağınıza iyi bir örnektir alignof(double)==4. Ancak std::atomic<double>hala alignof() = 8çalışma zamanında hizalamayı kontrol etmek yerine var. Atomik çizgiyi gereğinden az hizalayan paketlenmiş bir yapı kullanmak ABI'yi bozar ve desteklenmez. (32 bit x86 için GCC, 8 baytlık nesnelere doğal hizalama vermeyi tercih eder, ancak yapı paketleme kuralları bunu geçersiz kılar ve yalnızca alignof(T)i386 Sistem V'ye dayanır . G ++, atomic<int64_t>bir yapının içinde atomik olmayabilecek bir hataya sahipti çünkü sadece varsayıldı. GCC (C için değil C ++) hala bu hata var!)
Peter Cordes

2
Ancak doğru bir C ++ 20 uygulaması std::atomic_ref<double>ya doubletamamen hizalanmamış olarak reddeder ya da sade için yasal olduğu doubleve int64_tdoğal olarak daha az hizalanmış olduğu platformlarda çalışma zamanında hizalamayı kontrol eder . (Çünkü atomic_ref<T>düz olarak bildirilen bir nesne üzerinde çalışır Tve alignof(T)fazladan hizalama fırsatı olmadan yalnızca minimum hizalaması vardır .)
Peter Cordes

2
Bkz gcc.gnu.org/bugzilla/show_bug.cgi?id=62259 şimdi sabit libstdc ++ hata için ve gcc.gnu.org/bugzilla/show_bug.cgi?id=65146 a dahil hala kırık C hata için _Atomic int64_takımla derlendiğinde bir yırtılmayı gösteren saf ISO C11 test çantası gcc -m32. Her neyse, gerçek derleyiciler, hizalanmış atomikleri desteklemiyor ve çalışma zamanı kontrollerini (henüz?) Yapmıyorlar, #pragma packya __attribute__((packed))da sadece atomikliğe yol açmayacaklar; nesneler hala olduklarını rapor edecektir lock_free.
Peter Cordes

1
Ama evet, amacı is_lock_free()etmektir izin uygulamaları güncel olanları aslında yapmak biçimi farklı çalışma; HW destekli atomik talimatları kullanmak veya bir kilit kullanmak için gerçek hizalamaya dayalı çalışma zamanı kontrolleri.
Peter Cordes

3

Kullanabilirsin std::is_always_lock_free

is_lock_free gerçek sisteme bağlıdır ve derleme zamanında belirlenemez.

İlgili açıklama:

Atomik tiplerin bazen kilitsiz olmasına izin verilir, örneğin belirli bir mimaride yalnızca hizalanmış bellek erişimleri doğal olarak atomikse, aynı tipteki yanlış hizalanmış nesnelerin kilitleri kullanması gerekir.


1
std::numeric_limits<int>::maxmimariye bağlıdır, ancak statik ve constexpr. Sanırım cevapta yanlış bir şey yok, ama akıl yürütmenin ilk kısmını satın
almıyorum

1
Herhangi bir zamanda tanımlanmamış davranışa sahip olan dilin tanımlanmamış bir davranışa sahip olduğunu tanımlamıyor, böylece çalışma zamanında kilitsizliğin veya değerlendirilmesinin değerlendirilmesi saçmalık olacak mı?
Bonita Montero

1
Dil, ikincisini tanımsız davranış olarak tanımladığından, hizalanmış ve hizalanmamış erişim arasında karar vermek mantıklı değildir.
Bonita Montero

@BonitaMontero "C ++ nesne hizalamasında hizasız" ve "donanımın neye benzediğinde hizasız" duygusu vardır. Bunlar mutlaka aynı değildir, ancak pratikte sıklıkla vardır. Göstermek örnek derleyici görünen o ki, böyle bir örneğidir yerleşik iki varsayımına olan aynı - ki tek yolu o is_lock_freeanlamsız olduğunu derleyici üzerinde .
Max Langhof

1
Bir hizalama gereksinimi varsa, bir atomun düzgün hizalamaya sahip olacağından emin olabilirsiniz.
Bonita Montero

1

Visual Studio 2019'u Windows-PC'ye yükledim ve bu devenv'in de bir ARMv8 derleyicisi var. ARMv8, hizalanmamış erişime izin verir, ancak karşılaştırma ve takaslar, kilitli ekler vb. Hizalanacak şekilde zorunludur. Ayrıca ldpveya stp(yük çifti veya 32 bit kayıt depo çiftini) kullanan saf yük / saf deponun yalnızca doğal olarak hizalandıklarında atomik olmaları garanti edilir.

Bu yüzden rastgele bir atom-pointer için is_lock_free () döndürdüğünü kontrol etmek için küçük bir program yazdım. İşte kod:

#include <atomic>
#include <cstddef>

using namespace std;

bool isLockFreeAtomic( atomic<uint64_t> *a64 )
{
    return a64->is_lock_free();
}

Ve bu isLockFreeAtomic'in sökülmesi

|?isLockFreeAtomic@@YA_NPAU?$atomic@_K@std@@@Z| PROC
    movs        r0,#1
    bx          lr
ENDP

Bu sadece returns trueaka 1.

Bu uygulama, alignof( atomic<int64_t> ) == 8her atomic<int64_t>biri doğru şekilde hizalanacak şekilde kullanmayı seçer . Bu, her yükte ve depoda çalışma zamanı hizalama kontrolü ihtiyacını ortadan kaldırır.

(Editörün notu: Bu yaygındır; çoğu gerçek yaşam C ++ uygulamaları bu şekilde çalışan bu yüzden. std::is_always_lock_freeÖylesine yararlıdır: tipleri için genellikle çünkü doğru is_lock_free()zamankinden doğrudur.)


1
Evet, çoğu uygulama vermeyi seçer atomic<uint64_t>ve alignof() == 8bu nedenle çalışma zamanında hizalamayı kontrol etmeleri gerekmez. Bu eski API onlara bunu yapmama seçeneği sunar, ancak mevcut HW'de sadece hizalama gerektirmesi çok daha mantıklıdır (aksi takdirde UB, örneğin atomik olmayanlık). int64_tYalnızca 4 baytlık hizalamaya sahip olabilen 32 bitlik kodlarda bile atomic<int64_t>8 bayt gerektirir. Başka bir cevap
Peter Cordes

Farklı bir deyişle içine koyun: Eğer bir derleyici seçer yapmak için alignoftemel bir tip donanım "iyi" hizalama gibi aynı değeri, daha sonra is_lock_free hep olacak true(ve bu yüzden olacak is_always_lock_free). Derleyiciniz tam olarak bunu yapıyor. Ancak API, diğer derleyicilerin farklı şeyler yapabilmesi için var.
Max Langhof

1
Dil, hizalanmamış erişimin tanımlanmamış bir davranışa sahip olduğunu söylüyorsa, tüm atomiklerin düzgün bir şekilde hizalanması gerektiğinden emin olabilirsiniz. Hiçbir uygulama bu nedenle çalışma zamanı denetimi yapmaz.
Bonita Montero

@BonitaMontero Evet, ancak alignof(std::atomic<double>) == 1donanım double4'te s için yalnızca kilitsiz atomik işlemleri garanti edebilse bile, dilde yasaklayan hiçbir şey yoktur (bu nedenle C ++ anlamında "hizalanmamış erişim" olmaz, dolayısıyla UB olmaz). 8 bayt sınırı. Derleyicinin daha sonra hizalanmamış durumlarda kilitleri kullanması gerekir (ve is_lock_freenesne örneğinin bellek konumuna bağlı olarak uygun boole değerini döndürür ).
Max Langhof
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.