क्या कोई मुझे बता सकता है कि क्या std :: atomic :: is_lock_free () स्थिर होने के साथ-साथ स्थिर नहीं है? गैर-स्थैतिक और / या गैर-कॉन्स्ट्रेक्स होने से मुझे कोई मतलब नहीं है।
क्या कोई मुझे बता सकता है कि क्या std :: atomic :: is_lock_free () स्थिर होने के साथ-साथ स्थिर नहीं है? गैर-स्थैतिक और / या गैर-कॉन्स्ट्रेक्स होने से मुझे कोई मतलब नहीं है।
जवाबों:
जैसा कि cppreference पर समझाया गया है :
Std :: atomic_flag को छोड़कर सभी परमाणु प्रकारों को लॉक-फ्री परमाणु CPU निर्देशों का उपयोग करने के बजाय म्यूटेक्स या अन्य लॉकिंग ऑपरेशन का उपयोग करके लागू किया जा सकता है। परमाणु प्रकारों को भी कभी-कभी लॉक-फ़्री होने की अनुमति दी जाती है, उदाहरण के लिए, यदि केवल संरेखित मेमोरी एक्सेस किसी दिए गए आर्किटेक्चर पर स्वाभाविक रूप से परमाणु हैं, तो उसी प्रकार के गलत ऑब्जेक्ट्स को ताले का उपयोग करना होगा।
C ++ मानक अनुशंसा करता है (लेकिन इसकी आवश्यकता नहीं है) कि लॉक-फ्री परमाणु संचालन भी पता-मुक्त है, अर्थात साझा मेमोरी का उपयोग करके प्रक्रियाओं के बीच संचार के लिए उपयुक्त है।
जैसा कि कई अन्य लोगों ने उल्लेख किया है, std::is_always_lock_free
हो सकता है कि आप वास्तव में क्या देख रहे हों।
संपादित करें: स्पष्ट करने के लिए, C ++ ऑब्जेक्ट प्रकार में एक संरेखण मूल्य होता है जो उनके उदाहरणों के पते को केवल दो की शक्तियों के कुछ निश्चित गुणकों तक सीमित करता है ( [basic.align]
)। ये संरेखण मूल्य मौलिक प्रकारों के लिए कार्यान्वयन-परिभाषित हैं, और प्रकार के आकार की आवश्यकता नहीं है। वे उस हार्डवेयर से भी अधिक सख्त हो सकते हैं जो वास्तव में समर्थन कर सकता है।
उदाहरण के लिए, x86 (ज्यादातर) अनलगनेटेड एक्सेस का समर्थन करता है। हालाँकि, आपको सबसे अधिक संकलक alignof(double) == sizeof(double) == 8
x86 के लिए मिलेंगे , क्योंकि अनलग्टेड एक्सेस के पास नुकसान (गति, कैशिंग, एटमॉसिटी ...) का एक मेजबान है। लेकिन उदाहरण के लिए #pragma pack(1) struct X { char a; double b; };
या alignas(1) double x;
आपको "अ-असाइन" करने की अनुमति देता है double
। इसलिए जब cepreference "संरेखित मेमोरी एक्सेस" के बारे में बात करता है, तो यह संभवतः हार्डवेयर के प्रकार के प्राकृतिक संरेखण के संदर्भ में ऐसा करता है, न कि C ++ प्रकार का उपयोग इस तरह से करना कि इसकी संरेखण आवश्यकताओं (जो यूबी होगा) के विपरीत है।
यहाँ अधिक जानकारी है: x86 पर सफल अनलॉन्ग एक्सेस का वास्तविक प्रभाव क्या है?
कृपया नीचे @Peter Cordes द्वारा आनंददायक टिप्पणियों की जाँच करें!
alignof(double)==4
। लेकिन std::atomic<double>
अभी भी alignof() = 8
रनटाइम पर संरेखण की जाँच करने के बजाय है। एक पैक संरचना का उपयोग करना जो परमाणु को संरेखित करता है, एबीआई को तोड़ता है और समर्थित नहीं है। (32-बिट x86 के लिए GCC 8-बाइट ऑब्जेक्ट्स को प्राकृतिक संरेखण के लिए तरजीह देता है, लेकिन संरचना-पैकिंग नियम ओवरराइड करते हैं और केवल alignof(T)
I386 सिस्टम V. G ++ पर आधारित होते हैं , जहां एक बग होता है, जहां atomic<int64_t>
एक संरचना परमाणु नहीं हो सकती है। क्योंकि यह अभी मान लिया गया है। GCC (C नहीं C ++ के लिए) में अभी भी यह बग है!)
std::atomic_ref<double>
या तो double
पूरी तरह से अंडर-एलाइन को अस्वीकार कर देगा, या प्लेटफॉर्म पर रनटाइम पर संरेखण की जांच करेगा जहां यह सादे के लिए कानूनी है double
और int64_t
स्वाभाविक रूप से कम से कम संरेखित होना है। (क्योंकि atomic_ref<T>
एक ऐसी वस्तु पर काम होता है T
, जिसे एक सादा घोषित किया गया था , और केवल alignof(T)
अतिरिक्त संरेखण देने के अवसर के बिना एक न्यूनतम संरेखण है ।)
_Atomic int64_t
वर्तमान के साथ संकलित होने पर फाड़ दिखाता है gcc -m32
। वैसे भी, मेरी बात यह है कि वास्तविक संकलक अंडर-संरेखित एटॉमिक्स का समर्थन नहीं करते हैं, और रनटाइम चेक (अभी तक?) नहीं करते हैं, इसलिए #pragma pack
या __attribute__((packed))
केवल गैर-परमाणुता का नेतृत्व करेंगे; ऑब्जेक्ट अभी भी रिपोर्ट करेंगे कि वे हैं lock_free
।
is_lock_free()
करने की अनुमति देना है जो वर्तमान में वास्तव में करते हैं; एचडब्ल्यू समर्थित परमाणु निर्देशों का उपयोग करने या लॉक का उपयोग करने के लिए वास्तविक संरेखण के आधार पर रनटाइम चेक के साथ।
आप उपयोग कर सकते है std::is_always_lock_free
is_lock_free
वास्तविक प्रणाली पर निर्भर करता है और संकलन समय पर निर्धारित नहीं किया जा सकता है।
प्रासंगिक विवरण:
परमाणु प्रकारों को भी कभी-कभी लॉक-फ़्री होने की अनुमति दी जाती है, उदाहरण के लिए, यदि केवल संरेखित मेमोरी एक्सेस किसी दिए गए आर्किटेक्चर पर स्वाभाविक रूप से परमाणु होते हैं, तो उसी प्रकार के गलत ऑब्जेक्ट्स को ताले का उपयोग करना होगा।
std::numeric_limits<int>::max
वास्तुकला पर निर्भर करता है, फिर भी स्थिर है और constexpr
। मुझे लगता है कि उत्तर में कुछ भी गलत नहीं है, लेकिन मैं तर्क का पहला हिस्सा नहीं खरीदता हूं
is_lock_free
व्यर्थ है कि संकलक पर ।
मैंने अपने विंडोज-पीसी पर विजुअल स्टूडियो 2019 इंस्टॉल कर लिया है और इस डेवेव में ARMv8- कंपाइलर भी है। ARMv8 अनलग्ड एक्सेस की अनुमति देता है, लेकिन तुलना और स्वैप, लॉक किए गए आदि को संरेखित किया जाना अनिवार्य है। और यह भी शुद्ध भार / शुद्ध दुकान का उपयोग कर ldp
या stp
(लोड जोड़ी या 32-बिट रजिस्टरों की दुकान-जोड़ी) केवल जब वे स्वाभाविक रूप से गठबंधन कर रहे हैं परमाणु होने की गारंटी है।
इसलिए मैंने यह जांचने के लिए एक छोटा सा कार्यक्रम लिखा कि is_lock_free () एक मनमाना परमाणु-सूचक के लिए रिटर्न क्या है। तो यहाँ कोड है:
#include <atomic>
#include <cstddef>
using namespace std;
bool isLockFreeAtomic( atomic<uint64_t> *a64 )
{
return a64->is_lock_free();
}
और यह isLockFreeAtomic की disassembly है
|?isLockFreeAtomic@@YA_NPAU?$atomic@_K@std@@@Z| PROC
movs r0,#1
bx lr
ENDP
यह सिर्फ returns true
, उर्फ है 1
।
इस कार्यान्वयन का उपयोग करने के लिए चुनता है alignof( atomic<int64_t> ) == 8
ताकि हर atomic<int64_t>
सही ढंग से गठबंधन किया गया हो। यह हर लोड और स्टोर पर रनटाइम संरेखण जांच की आवश्यकता से बचा जाता है।
(संपादक का ध्यान दें: यह सामान्य है; अधिकांश वास्तविक-जीवन C ++ कार्यान्वयन इसी तरह से काम करते हैं। यही कारण std::is_always_lock_free
है कि यह बहुत उपयोगी है: क्योंकि यह आमतौर पर उन प्रकारों के लिए सच है जहां is_lock_free()
कभी भी सत्य होता है।)
atomic<uint64_t>
और alignof() == 8
इसलिए उन्हें रनटाइम पर संरेखण की जांच करने की आवश्यकता नहीं होती है। यह पुराना एपीआई उन्हें ऐसा नहीं करने का विकल्प देता है, लेकिन वर्तमान एचडब्ल्यू पर यह सिर्फ संरेखण (अन्यथा यूबी, जैसे गैर-परमाणुता) की आवश्यकता के लिए बहुत अधिक समझ में आता है। यहां तक कि 32-बिट कोड में जहां int64_t
केवल 4-बाइट संरेखण हो सकता है, atomic<int64_t>
8-बाइट की आवश्यकता होती है। एक अन्य उत्तर पर मेरी टिप्पणी
alignof
एक मौलिक प्रकार के लिए मूल्य बनाने का विकल्प चुनता है, जैसे कि हार्डवेयर का "अच्छा" संरेखण, तो is_lock_free
हमेशा true
(और ऐसा ही is_always_lock_free
) होगा । यहां आपका कंपाइलर बिल्कुल यही करता है। लेकिन एपीआई मौजूद है इसलिए अन्य कंपाइलर अलग-अलग चीजें कर सकते हैं।
alignof(std::atomic<double>) == 1
(इसलिए C ++ अर्थ में "अनलगिनेटेड एक्सेस" नहीं होगा, इसलिए कोई UB) नहीं है, भले ही हार्डवेयर केवल double
4 पर s के लिए लॉक-फ्री परमाणु संचालन की गारंटी दे सकता है 8 बाइट की सीमा। कंपाइलर को तब अनलग किए गए मामलों में ताले का उपयोग करना होगा (और is_lock_free
ऑब्जेक्ट उदाहरण के मेमोरी लोकेशन के आधार पर उपयुक्त बूलियन मान लौटाएं )।
is_always_lock_free
?