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.
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.
Yanıtlar:
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) == 8
hizalanmamış 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ış" double
lara 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 !
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!)
std::atomic_ref<double>
ya double
tamamen hizalanmamış olarak reddeder ya da sade için yasal olduğu double
ve int64_t
doğ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 T
ve alignof(T)
fazladan hizalama fırsatı olmadan yalnızca minimum hizalaması vardır .)
_Atomic int64_t
akı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 pack
ya __attribute__((packed))
da sadece atomikliğe yol açmayacaklar; nesneler hala olduklarını rapor edecektir lock_free
.
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.
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.
std::numeric_limits<int>::max
mimariye 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
is_lock_free
anlamsız olduğunu derleyici üzerinde .
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 ldp
veya 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 true
aka 1
.
Bu uygulama, alignof( atomic<int64_t> ) == 8
her 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.)
atomic<uint64_t>
ve alignof() == 8
bu 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_t
Yalnızca 4 baytlık hizalamaya sahip olabilen 32 bitlik kodlarda bile atomic<int64_t>
8 bayt gerektirir. Başka bir cevap
alignof
temel 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.
alignof(std::atomic<double>) == 1
donanım double
4'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_free
nesne örneğinin bellek konumuna bağlı olarak uygun boole değerini döndürür ).
is_always_lock_free
?