क्यों std :: atomic <T> :: is_lock_free () स्थिर नहीं है और साथ ही साथ कॉन्स्टैक्स?


9

क्या कोई मुझे बता सकता है कि क्या std :: atomic :: is_lock_free () स्थिर होने के साथ-साथ स्थिर नहीं है? गैर-स्थैतिक और / या गैर-कॉन्स्ट्रेक्स होने से मुझे कोई मतलब नहीं है।


3
क्या आप जानते हैं is_always_lock_free?
माइक वैन डाइक

3
मैं वहाँ से "संरेखण" फेंकने जा रहा हूँ।
मैक्स लैंगहॉफ़

@MaxLanghof क्या आपका मतलब है कि सभी उदाहरणों को एक ही तरह संरेखित नहीं किया जाएगा?
जिज्ञासु

1
माइक, नहीं, मुझे पता नहीं था, लेकिन इस संकेत के लिए धन्यवाद; यह मेरे लिए बहुत उपयोगी है। लेकिन मैं खुद से पूछ रहा हूं कि is_lock_free () और is_always_lock_free के बीच कोई निर्णय क्यों है। यह अनछुए परमाणुओं की वजह से नहीं हो सकता है, अन्य लोगों ने यहां सुझाव दिया है, क्योंकि भाषा अनलॉगटेड एक्सेस को परिभाषित करती है, ताकि किसी भी तरह का अपरिभाषित व्यवहार हो।
बोनिता मोंटेरो

जवाबों:


10

जैसा कि cppreference पर समझाया गया है :

Std :: atomic_flag को छोड़कर सभी परमाणु प्रकारों को लॉक-फ्री परमाणु CPU निर्देशों का उपयोग करने के बजाय म्यूटेक्स या अन्य लॉकिंग ऑपरेशन का उपयोग करके लागू किया जा सकता है। परमाणु प्रकारों को भी कभी-कभी लॉक-फ़्री होने की अनुमति दी जाती है, उदाहरण के लिए, यदि केवल संरेखित मेमोरी एक्सेस किसी दिए गए आर्किटेक्चर पर स्वाभाविक रूप से परमाणु हैं, तो उसी प्रकार के गलत ऑब्जेक्ट्स को ताले का उपयोग करना होगा।

C ++ मानक अनुशंसा करता है (लेकिन इसकी आवश्यकता नहीं है) कि लॉक-फ्री परमाणु संचालन भी पता-मुक्त है, अर्थात साझा मेमोरी का उपयोग करके प्रक्रियाओं के बीच संचार के लिए उपयुक्त है।

जैसा कि कई अन्य लोगों ने उल्लेख किया है, std::is_always_lock_freeहो सकता है कि आप वास्तव में क्या देख रहे हों।


संपादित करें: स्पष्ट करने के लिए, C ++ ऑब्जेक्ट प्रकार में एक संरेखण मूल्य होता है जो उनके उदाहरणों के पते को केवल दो की शक्तियों के कुछ निश्चित गुणकों तक सीमित करता है ( [basic.align])। ये संरेखण मूल्य मौलिक प्रकारों के लिए कार्यान्वयन-परिभाषित हैं, और प्रकार के आकार की आवश्यकता नहीं है। वे उस हार्डवेयर से भी अधिक सख्त हो सकते हैं जो वास्तव में समर्थन कर सकता है।

उदाहरण के लिए, x86 (ज्यादातर) अनलगनेटेड एक्सेस का समर्थन करता है। हालाँकि, आपको सबसे अधिक संकलक alignof(double) == sizeof(double) == 8x86 के लिए मिलेंगे , क्योंकि अनलग्टेड एक्सेस के पास नुकसान (गति, कैशिंग, एटमॉसिटी ...) का एक मेजबान है। लेकिन उदाहरण के लिए #pragma pack(1) struct X { char a; double b; };या alignas(1) double x;आपको "अ-असाइन" करने की अनुमति देता है double। इसलिए जब cepreference "संरेखित मेमोरी एक्सेस" के बारे में बात करता है, तो यह संभवतः हार्डवेयर के प्रकार के प्राकृतिक संरेखण के संदर्भ में ऐसा करता है, न कि C ++ प्रकार का उपयोग इस तरह से करना कि इसकी संरेखण आवश्यकताओं (जो यूबी होगा) के विपरीत है।

यहाँ अधिक जानकारी है: x86 पर सफल अनलॉन्ग एक्सेस का वास्तविक प्रभाव क्या है?

कृपया नीचे @Peter Cordes द्वारा आनंददायक टिप्पणियों की जाँच करें!


1
32-बिट x86 एक अच्छा उदाहरण है जहां आप ABI को ढूंढते हैं alignof(double)==4। लेकिन std::atomic<double>अभी भी alignof() = 8रनटाइम पर संरेखण की जाँच करने के बजाय है। एक पैक संरचना का उपयोग करना जो परमाणु को संरेखित करता है, एबीआई को तोड़ता है और समर्थित नहीं है। (32-बिट x86 के लिए GCC 8-बाइट ऑब्जेक्ट्स को प्राकृतिक संरेखण के लिए तरजीह देता है, लेकिन संरचना-पैकिंग नियम ओवरराइड करते हैं और केवल alignof(T)I386 सिस्टम V. G ++ पर आधारित होते हैं , जहां एक बग होता है, जहां atomic<int64_t>एक संरचना परमाणु नहीं हो सकती है। क्योंकि यह अभी मान लिया गया है। GCC (C नहीं C ++ के लिए) में अभी भी यह बग है!)
पीटर कॉर्ड्स

2
लेकिन C ++ 20 का एक सही क्रियान्वयन std::atomic_ref<double>या तो doubleपूरी तरह से अंडर-एलाइन को अस्वीकार कर देगा, या प्लेटफॉर्म पर रनटाइम पर संरेखण की जांच करेगा जहां यह सादे के लिए कानूनी है doubleऔर int64_tस्वाभाविक रूप से कम से कम संरेखित होना है। (क्योंकि atomic_ref<T>एक ऐसी वस्तु पर काम होता है T, जिसे एक सादा घोषित किया गया था , और केवल alignof(T)अतिरिक्त संरेखण देने के अवसर के बिना एक न्यूनतम संरेखण है ।)
पीटर कॉर्डेस

2
अभी भी टूटे हुए सी बग के लिए gcc.gnu.org/bugzilla/show_bug.cgi?id=62259 देखें , जो अब-निर्धारित libstdc ++ बग के लिए है, और gcc.gnu.org/bugzilla/show_buggi.gi?id=65146 शुद्ध आईएसओ C11 टेस्टकेस जो _Atomic int64_tवर्तमान के साथ संकलित होने पर फाड़ दिखाता है gcc -m32। वैसे भी, मेरी बात यह है कि वास्तविक संकलक अंडर-संरेखित एटॉमिक्स का समर्थन नहीं करते हैं, और रनटाइम चेक (अभी तक?) नहीं करते हैं, इसलिए #pragma packया __attribute__((packed))केवल गैर-परमाणुता का नेतृत्व करेंगे; ऑब्जेक्ट अभी भी रिपोर्ट करेंगे कि वे हैं lock_free
पीटर कॉर्डेस

1
लेकिन हां, इसका उद्देश्य कार्यान्वयन को उस तरह से अलग तरीके से काम is_lock_free()करने की अनुमति देना है जो वर्तमान में वास्तव में करते हैं; एचडब्ल्यू समर्थित परमाणु निर्देशों का उपयोग करने या लॉक का उपयोग करने के लिए वास्तविक संरेखण के आधार पर रनटाइम चेक के साथ।
पीटर कॉर्डेस

3

आप उपयोग कर सकते है std::is_always_lock_free

is_lock_free वास्तविक प्रणाली पर निर्भर करता है और संकलन समय पर निर्धारित नहीं किया जा सकता है।

प्रासंगिक विवरण:

परमाणु प्रकारों को भी कभी-कभी लॉक-फ़्री होने की अनुमति दी जाती है, उदाहरण के लिए, यदि केवल संरेखित मेमोरी एक्सेस किसी दिए गए आर्किटेक्चर पर स्वाभाविक रूप से परमाणु होते हैं, तो उसी प्रकार के गलत ऑब्जेक्ट्स को ताले का उपयोग करना होगा।


1
std::numeric_limits<int>::maxवास्तुकला पर निर्भर करता है, फिर भी स्थिर है और constexpr। मुझे लगता है कि उत्तर में कुछ भी गलत नहीं है, लेकिन मैं तर्क का पहला हिस्सा नहीं खरीदता हूं
idclev 463035818

1
क्या भाषा को परिभाषित नहीं किया गया है ताकि किसी भी तरह का अपरिभाषित व्यवहार न हो ताकि लॉक-फ़्री-नेस का मूल्यांकन हो या रनटाइम पर नॉनसेंस न हो?
बोनिता मोनटेरो

1
भाषा के उत्तरार्द्ध को अपरिभाषित व्यवहार के रूप में परिभाषित करने के लिए यह संरेखित और असम्बद्ध पहुंच के बीच निर्णय लेने का कोई मतलब नहीं है।
बोनिता मोनटेरो

@BonitaMontero "C ++ ऑब्जेक्ट एलाइनमेंट" अर्थ में "अनलग्ड" है और "हार्डवेयर पसंद करता है" में अलिखित है। वे जरूरी समान नहीं हैं, लेकिन व्यवहार में वे अक्सर हैं। उदाहरण आपको बताएंगे कि ऐसे ही एक उदाहरण है जहां संकलक जाहिरा तौर पर किया गया है में निर्मित धारणा है कि दो हैं एक ही है - जो केवल अर्थ यह है कि is_lock_freeव्यर्थ है कि संकलक पर
मैक्स लैंगहॉफ

1
यदि आप एक संरेखण की आवश्यकता है, तो आप यह सुनिश्चित कर सकते हैं कि एक परमाणु का उचित संरेखण होगा।
बोनिता मोंटेरो

1

मैंने अपने विंडोज-पीसी पर विजुअल स्टूडियो 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()कभी भी सत्य होता है।)


1
हां, अधिकांश कार्यान्वयन देने के लिए चुनते हैं atomic<uint64_t>और alignof() == 8इसलिए उन्हें रनटाइम पर संरेखण की जांच करने की आवश्यकता नहीं होती है। यह पुराना एपीआई उन्हें ऐसा नहीं करने का विकल्प देता है, लेकिन वर्तमान एचडब्ल्यू पर यह सिर्फ संरेखण (अन्यथा यूबी, जैसे गैर-परमाणुता) की आवश्यकता के लिए बहुत अधिक समझ में आता है। यहां तक ​​कि 32-बिट कोड में जहां int64_tकेवल 4-बाइट संरेखण हो सकता है, atomic<int64_t>8-बाइट की आवश्यकता होती है। एक अन्य उत्तर पर मेरी टिप्पणी
पीटर कॉर्ड्स

अलग-अलग शब्दों में रखें: यदि कोई कंपाइलर alignofएक मौलिक प्रकार के लिए मूल्य बनाने का विकल्प चुनता है, जैसे कि हार्डवेयर का "अच्छा" संरेखण, तो is_lock_free हमेशा true(और ऐसा ही is_always_lock_free) होगा । यहां आपका कंपाइलर बिल्कुल यही करता है। लेकिन एपीआई मौजूद है इसलिए अन्य कंपाइलर अलग-अलग चीजें कर सकते हैं।
मैक्स लैंगहॉफ

1
आप इस बात से निश्चिंत हो सकते हैं कि यदि भाषा कहती है कि अन-असाइन किए गए पहुँच में अपरिभाषित व्यवहार है, तो सभी परमाणुओं को ठीक से संरेखित करना होगा। कोई भी क्रियान्वयन उस वजह से कोई रनटाइम-चेक नहीं करेगा।
बोनिता मोंटेरो

@BonitaMontero हां, लेकिन भाषा में ऐसा कुछ भी नहीं है जो निषिद्ध हो alignof(std::atomic<double>) == 1(इसलिए C ++ अर्थ में "अनलगिनेटेड एक्सेस" नहीं होगा, इसलिए कोई UB) नहीं है, भले ही हार्डवेयर केवल double4 पर s के लिए लॉक-फ्री परमाणु संचालन की गारंटी दे सकता है 8 बाइट की सीमा। कंपाइलर को तब अनलग किए गए मामलों में ताले का उपयोग करना होगा (और is_lock_freeऑब्जेक्ट उदाहरण के मेमोरी लोकेशन के आधार पर उपयुक्त बूलियन मान लौटाएं )।
मैक्स लैंगहॉफ
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.