C ++ std :: memory_order_relaxed भ्रम

Oct 12 2020

मैं C ++ मेमोरी बैरियर (और इसके कमाल) के बारे में जीसीसी विकी के इस लेख को पढ़ रहा था ।
जब तक मैं इस बिंदु पर नहीं आया तब तक यह बहुत सीधा था:

विपरीत दृष्टिकोण std :: memory_order_relaxed है। यह मॉडल होता है-पहले प्रतिबंधों को हटाकर बहुत कम सिंक्रनाइज़ेशन की अनुमति देता है। इस प्रकार के परमाणु संचालन में उन पर किए गए विभिन्न अनुकूलन भी हो सकते हैं, जैसे कि डेड स्टोर हटाना और आम करना। तो पहले के उदाहरण में:

-Thread 1-
y.store (20, memory_order_relaxed)
x.store (10, memory_order_relaxed)

-Thread 2-
if (x.load (memory_order_relaxed) == 10)
  {
    assert (y.load(memory_order_relaxed) == 20) /* assert A */
    y.store (10, memory_order_relaxed)
  }

-Thread 3-
if (y.load (memory_order_relaxed) == 10)
  assert (x.load(memory_order_relaxed) == 10) /* assert B */

चूंकि थ्रेड्स को पूरे सिस्टम में सिंक्रनाइज़ करने की आवश्यकता नहीं है, या तो इस उदाहरण में मुखर वास्तव में विफल हो सकता है।

ठीक है, यह सीधा है, चलो पर ले जाने के लिए ..

-Thread 1-
x.store (1, memory_order_relaxed)
x.store (2, memory_order_relaxed)

-Thread 2-
y = x.load (memory_order_relaxed)
z = x.load (memory_order_relaxed)
assert (y <= z)

मुखर विफल नहीं हो सकता। एक बार 2 के स्टोर को थ्रेड 2 द्वारा देखा जाता है, यह अब मान नहीं देख सकता है। यह एक अलग संदर्भ के आराम से लोड भर में एक चर के आरामदायक लोड को रोकने से रोकता है जो अन्य नाम हो सकता है।

यह वही है जो मुझे भ्रमित करता है, क्यों y मान 2 लोड नहीं कर सकता और z मान 1 लोड करता है (और विफल होने का कारण बनता है), क्योंकि ऑर्डर 1 थ्रेड में सिंक्रनाइज़ नहीं है?

जवाब

4 NicolBolas Oct 12 2020 at 12:12

रिलैक्स्ड ऑर्डर अन्य मेमोरी एक्सेस के संबंध में ऑपरेशंस के ऑर्डरिंग के सापेक्ष है, एटॉमिक रिलेटेड रिलेक्स-रिवाइंड होने के सापेक्ष ऑर्डर नहीं कर रहा है। आपके पहले मामले में, जिस तथ्य को आप 10 देख सकते हैं, xउसके मूल्य के संबंध में कुछ भी मतलब नहीं है y। और इसके विपरीत।

लेकिन आपका दूसरा मामला अलग है, क्योंकि यह एक ही परमाणु वस्तु को प्रभावित कर रहा है।

[intro.races] / 10 हमें बताता है कि, एक धागे के भीतर, यदि एक ऑपरेशन दूसरे से पहले अनुक्रमित होता है, तो वह ऑपरेशन "दूसरे से पहले" होता है। और [intro.races] / 14-17 परमाणुओं के संबंध में निम्नलिखित व्यवहार को रेखांकित करते हैं :

चार पूर्ववर्ती सुसंगतता आवश्यकताओं को प्रभावी ढंग से एक ही वस्तु के लिए परमाणु संचालन के संकलक पुन: व्यवस्थित करना, भले ही दोनों आपरेशनों को आराम से लोड हो।

और यही तुम्हारे यहाँ है। सभी संशोधन एक ही वस्तु के लिए हो रहे हैं, इसलिए उन्हें कुछ क्रम में होना चाहिए । यहां तक ​​कि अगर उस आदेश को ठीक से निर्धारित नहीं किया जा सकता है, तो आदेश को कोड के संबंधों के "पहले होता है" का सम्मान करना चाहिए।

थ्रेड 1 के दो संचालन "रिश्ते से पहले होता है" द्वारा आदेश दिया जाता है। और थ्रेड 2 के संचालन खुद एक "रिश्ते से पहले होता है" द्वारा आदेश दिया जाता है।

चूँकि वे सभी एक ही परमाणु वस्तु पर कार्य कर रहे हैं, यदि y2 का मान मिलता है, तो यह " xसेट होने के बाद" 2 xहो गया होगा । इसलिए "x = 1, x = 2" के लिए एक्सेस का क्रम होना चाहिए था एक्स पढ़ें ”। और जब से xपहली बार पढ़ने के बाद होता है , तब अंतिम xमान 1 हो सकता है।