मल्टी थ्रेडिंग के साथ वाष्पशील का उपयोग कब करें?


130

यदि वैश्विक चर पर पहुंचने वाले दो धागे हैं, तो कई ट्यूटोरियल कहते हैं कि चर को एक रजिस्टर में चर को संकलित करने से रोकने के लिए परिवर्तनशील अस्थिर है और यह इस प्रकार सही ढंग से अपडेट नहीं हो रहा है। हालाँकि, दोनों साझा चर को एक्सेस करने वाले दो धागे एक ऐसी चीज है जो म्यूटेक्स के माध्यम से सुरक्षा के लिए कहता है? लेकिन उस मामले में, थ्रेड लॉक करने और म्यूटेक्स को जारी करने के बीच कोड एक महत्वपूर्ण खंड में होता है, जहां केवल एक धागा चर तक पहुंच सकता है, उस स्थिति में चर को अस्थिर होने की आवश्यकता नहीं है?

तो इसलिए बहु-सूत्रीय कार्यक्रम में अस्थिरता का उपयोग / उद्देश्य क्या है?


3
कुछ मामलों में, आप म्यूटेक्स द्वारा सुरक्षा / आवश्यकता नहीं चाहते हैं।
स्टीफन माई

4
कभी-कभी इसकी दौड़ की स्थिति ठीक होती है, कभी-कभी ऐसा नहीं होता है। आप इस चर का उपयोग कैसे कर रहे हैं?
डेविड हेफर्नन

3
@ दाविद: जब रेस के लिए "फाइन" करना हो, तो कृपया इसका एक उदाहरण?
जॉन डिब्लिंग

6
@ जॉन यहाँ जाता है। कल्पना कीजिए कि आपके पास एक श्रमिक धागा है जो कई कार्यों को संसाधित कर रहा है। जब भी कोई कार्य पूरा होता है तो श्रमिक सूत्र एक काउंटर बढ़ाता है। मास्टर थ्रेड समय-समय पर इस काउंटर को पढ़ता है और प्रगति की खबर के साथ उपयोगकर्ता को अपडेट करता है। जब तक काउंटर को फाड़ने से बचने के लिए ठीक से संरेखित किया जाता है, तब तक एक्सेस को सिंक्रनाइज़ करने की कोई आवश्यकता नहीं है। हालांकि एक दौड़ है, यह सौम्य है।
डेविड हेफर्नन

5
@ जॉन यह कोड जिस हार्डवेयर पर चलता है वह गारंटी देता है कि संरेखित चर फाड़ से पीड़ित नहीं हो सकते। यदि कार्यकर्ता n + 1 को पाठक के रूप में पढ़ रहा है, तो पाठक परवाह नहीं करता है कि उन्हें n या n + 1 मिलता है या नहीं। कोई महत्वपूर्ण निर्णय नहीं लिया जाएगा क्योंकि इसका उपयोग केवल प्रगति रिपोर्टिंग के लिए किया जाता है।
डेविड हेफर्नन

जवाबों:


167

संक्षिप्त और त्वरित उत्तर : volatile(लगभग) मंच-अज्ञेय, बहुपरत अनुप्रयोग प्रोग्रामिंग के लिए बेकार है। यह कोई सिंक्रनाइज़ेशन प्रदान नहीं करता है, यह मेमोरी बाड़ नहीं बनाता है, और न ही यह संचालन के निष्पादन का क्रम सुनिश्चित करता है। यह ऑपरेशन को परमाणु नहीं बनाता है। यह आपके कोड को जादुई रूप से सुरक्षित नहीं बनाता है। volatileC ++ के सभी में सबसे अधिक गलत समझा सुविधा हो सकती है। इसके बारे में अधिक जानकारी के लिए इसे , यह और इसे देखेंvolatile

दूसरी ओर, volatileकुछ उपयोग है कि इतना स्पष्ट नहीं हो सकता है। यह उसी तरह से उपयोग किया जा सकता है जिस तरह से constआप कंपाइलर को दिखाने में मदद करने के लिए उपयोग करेंगे जहां आप गैर-संरक्षित तरीके से कुछ साझा संसाधन तक पहुंचने में गलती कर सकते हैं। इस प्रयोग की चर्चा अलेक्जेंड्रेस्कु ने इस लेख में की है । हालाँकि, यह मूल रूप से C ++ प्रकार की प्रणाली का उपयोग कर रहा है, जिसे अक्सर एक अंतर्विरोध के रूप में देखा जाता है और अनिर्धारित व्यवहार को जन्म दे सकता है।

volatileमेमोरी-मैप्ड हार्डवेयर, सिग्नल हैंडलर और सेटजम्प मशीन कोड इंस्ट्रक्शन के साथ इंटरफेस करते समय विशेष रूप से इसका उपयोग करने का इरादा था। यह volatileसामान्य एप्लिकेशन-स्तरीय प्रोग्रामिंग के बजाय सिस्टम-स्तरीय प्रोग्रामिंग पर सीधे लागू होता है।

2003 सी ++ मानक यह नहीं कहता है कि volatileचर पर किसी भी प्रकार के एक्वायर या रिलीज शब्दार्थ को लागू करता है । वास्तव में, मल्टीथ्रेडिंग के सभी मामलों पर मानक पूरी तरह से चुप है। हालाँकि, विशिष्ट प्लेटफ़ॉर्म volatileचर पर एक्वायर और रिलीज़ शब्दार्थ लागू करते हैं ।

[C ++ 11 के लिए अपडेट करें]

C ++ 11 मानक अब मेमोरी मॉडल और लैन्यूज में सीधे मल्टीथ्रेडिंग को स्वीकार करता है , और यह प्लेटफ़ॉर्म-स्वतंत्र तरीके से इससे निपटने के लिए लाइब्रेरी की सुविधा प्रदान करता है। हालाँकि volatileअभी भी शब्दार्थ नहीं बदला है। volatileअभी भी एक सिंक्रनाइज़ेशन तंत्र नहीं है। Bjarne Stroustrup कहते हैं जितना TCPPPL4E में है:

volatileनिम्न-स्तरीय कोड को छोड़कर उपयोग न करें जो सीधे हार्डवेयर के साथ काम करता है।

मान लें volatileकि मेमोरी मॉडल में विशेष अर्थ नहीं है । ऐसा नहीं होता। यह नहीं है - जैसा कि कुछ बाद की भाषाओं में है - एक सिंक्रनाइज़ेशन तंत्र। सिंक्रनाइज़ेशन प्राप्त करने के लिए, उपयोग atomic, ए mutex, या ए condition_variable

[/ अंतिम अद्यतन]

2003 के मानक (और अब 2011 के मानक) द्वारा परिभाषित सभी उपरोक्त सी ++ भाषा पर ही लागू होते हैं। हालाँकि, कुछ विशिष्ट प्लेटफ़ॉर्म अतिरिक्त कार्यक्षमता या प्रतिबंधों को जोड़ते हैं volatile। उदाहरण के लिए, MSVC 2010 में (कम से कम) को प्राप्त करने और रिलीज अर्थ विज्ञान है निश्चित संचालनों के लिए पर लागू volatileचर। MSDN से :

अनुकूलन करते समय, संकलक को अस्थिर वस्तुओं के साथ-साथ अन्य वैश्विक वस्तुओं के संदर्भ में आदेश बनाए रखना चाहिए। विशेष रूप से,

वाष्पशील वस्तु (वाष्पशील लेखन) के लिए एक रिलीज में अर्थ शब्दार्थ होता है; एक वैश्विक या स्थैतिक वस्तु का संदर्भ जो अनुदेश अनुक्रम में एक वाष्पशील वस्तु के लिए लिखने से पहले होता है, संकलित बाइनरी में उस अस्थिर लेखन से पहले होगा।

वाष्पशील वस्तु (वाष्पशील वाचन) की एक रीड में एकांत शब्दार्थ है; एक वैश्विक या स्थिर वस्तु का संदर्भ जो अनुदेश अनुक्रम में अस्थिर स्मृति के एक पढ़ने के बाद होता है, वह उस संकलन बाइनरी में वाष्पशील पढ़ने के बाद होगा।

हालाँकि, आप इस तथ्य पर ध्यान दे सकते हैं कि यदि आप उपरोक्त लिंक का अनुसरण करते हैं, तो टिप्पणियों में कुछ बहस है कि क्या इस मामले में सिमेंटिक्स वास्तव में लागू होते हैं या नहीं प्राप्त होते हैं।


19
जवाब के कृपालु स्वर और पहली टिप्पणी के कारण मेरा कुछ हिस्सा इसे कम करना चाहता है। "अस्थिर बेकार है" "मैनुअल मेमोरी आवंटन बेकार है" के समान है। यदि आप volatileइसके बिना एक मल्टीथ्रेडेड प्रोग्राम लिख सकते हैं , क्योंकि आप उन लोगों के कंधों पर खड़े थे जो volatileथ्रेडिंग लाइब्रेरी को लागू करते थे।
बेन जैक्सन

19
@ सिर्फ इसलिए कि आपके विश्वासों को चुनौती देने वाली कोई चीज इसे कृपालु नहीं बनाती
डेविड हेफर्नन

38
@ बान: नहीं, volatileवास्तव में C ++ में क्या करता है , इस पर पढ़ें । @ जॉन ने जो कहा वह सही है , कहानी का अंत है। इसका उस मामले के लिए आवेदन कोड बनाम लाइब्रेरी कोड, या "साधारण" बनाम "ईश्वर-जैसा सर्वज्ञ कार्यक्रम" से कोई लेना-देना नहीं है। volatileधागे के बीच तुल्यकालन के लिए अनावश्यक और बेकार है। थ्रेडिंग पुस्तकालयों के संदर्भ में लागू नहीं किया जा सकता है volatile; इसे वैसे भी प्लेटफ़ॉर्म-विशिष्ट विवरणों पर निर्भर रहना पड़ता है, और जब आप उन पर भरोसा करते हैं, तो आपको कोई ज़रूरत नहीं है volatile
jalf

6
@jalf: "थ्रेड्स के बीच सिंक्रोनाइज़ेशन के लिए अस्थिरता अनावश्यक और बेकार है" (जो आपने कहा है) वही नहीं है जो "मल्टीथ्रेडेड प्रोग्रामिंग के लिए अस्थिर है" (जो कि जॉन ने उत्तर में कहा है)। आप 100% सही हैं, लेकिन मैं जॉन (आंशिक रूप से) से असहमत हूं - अस्थिर को अभी भी मल्टीथ्रेडेड प्रोग्रामिंग (बहुत सीमित कार्यों के लिए) के लिए इस्तेमाल किया जा सकता है

4
@ मन: जो कुछ भी उपयोगी है वह आवश्यकताओं या शर्तों के एक निश्चित सेट के तहत ही उपयोगी है। अस्थिर स्थितियों के एक सख्त सेट के तहत (और कुछ मामलों में, बेहतर से बेहतर कुछ परिभाषा के लिए) बेहतर हो सकता है। आप कहते हैं कि "इस बात को अनदेखा करना और .." लेकिन जब बहुक्रियाशील के लिए वाष्पशील उपयोगी होता है तो ऐसा कुछ भी अनदेखा नहीं करता है। आपने कुछ ऐसा बना दिया जिसका मैंने कभी दावा नहीं किया। हां, अस्थिरता की उपयोगिता सीमित है, लेकिन यह मौजूद है - लेकिन हम सभी सहमत हो सकते हैं कि यह सिंक्रनाइज़ेशन के लिए उपयोगी नहीं है।

31

(संपादक का ध्यान दें: C ++ 11 volatileमें इस नौकरी के लिए सही उपकरण नहीं है और अभी भी डेटा-रेस यूबी है। यूबी के बिना ऐसा करने के लिए लोड / स्टोर के std::atomic<bool>साथ उपयोग करें std::memory_order_relaxed। वास्तविक कार्यान्वयन पर यह उसी के अनुरूप होगा volatile। अधिक विस्तार के साथ एक उत्तर , और टिप्पणियों में गलतफहमी को संबोधित करते हुए कि कमजोर-आदेश वाली मेमोरी इस उपयोग-मामले के लिए एक समस्या हो सकती है: सभी वास्तविक दुनिया के सीपीयू में सुसंगत साझा मेमोरी है इसलिए यह वास्तविक C ++ कार्यान्वयन पर volatileकाम करेगा । 'यह मत करो।

टिप्पणियों में कुछ चर्चा अन्य उपयोग-मामलों के बारे में बात करती हुई प्रतीत होती है जहाँ आपको आराम से परमाणु की तुलना में कुछ मजबूत करने की आवश्यकता होगी । यह उत्तर पहले ही इंगित करता है volatileजो आपको कोई आदेश नहीं देता है।)


वाष्पशील कभी-कभी निम्न कारण से उपयोगी होता है: यह कोड:

/* global */ bool flag = false;

while (!flag) {}

Gcc द्वारा अनुकूलित किया गया है:

if (!flag) { while (true) {} }

जो स्पष्ट रूप से गलत है यदि झंडा दूसरे धागे से लिखा गया है। ध्यान दें कि इस अनुकूलन के बिना सिंक्रनाइज़ेशन तंत्र शायद काम करता है (अन्य कोड के आधार पर कुछ मेमोरी बाधाओं की आवश्यकता हो सकती है) - 1 निर्माता - 1 उपभोक्ता परिदृश्य में म्यूटेक्स की कोई आवश्यकता नहीं है।

अन्यथा अस्थिर कीवर्ड प्रयोग करने योग्य होने के लिए बहुत अजीब है - यह किसी भी मेमोरी ऑर्डरिंग की गारंटी नहीं देता है, जो अस्थिर और गैर-वाष्पशील दोनों प्रकार के एक्सेस की गारंटी देता है और कोई भी परमाणु संचालन प्रदान नहीं करता है - अर्थात आपको वाष्पशील कीवर्ड के साथ कंपाइलर से कोई मदद नहीं मिलती है सिवाय रजिस्टर रजिस्टर कैशिंग के ।


4
अगर मुझे याद है, C ++ 0x परमाणु, ठीक से करने के लिए है जो बहुत से लोग मानते हैं (गलत तरीके से) अस्थिर द्वारा किया जाता है।
डेविड हेफर्नन

13
volatileस्मृति अभिगमन को पुन: व्यवस्थित होने से नहीं रोकता है। volatileएक्सेस को एक-दूसरे के सम्मान के साथ फिर से व्यवस्थित नहीं किया जाएगा, लेकिन वे गैर- ऑब्जेक्ट के संबंध में पुन: व्यवस्थित करने के बारे में कोई गारंटी नहीं देते volatileहैं, और इसलिए, वे मूल रूप से झंडे के रूप में भी बेकार हैं।
jalf

13
@: मुझे लगता है कि आप इसे उल्टा कर दिया है। "अस्थिर बेकार है" भीड़ इस तथ्य पर निर्भर करती है कि अस्थिरता रीऑर्डरिंग से रक्षा नहीं करती है , जिसका अर्थ है कि यह सिंक्रनाइज़ेशन के लिए पूरी तरह से बेकार है। अन्य दृष्टिकोण समान रूप से बेकार हो सकते हैं (जैसा कि आप उल्लेख करते हैं, लिंक-टाइम कोड अनुकूलन कंपाइलर को कोड में झांकने की अनुमति दे सकता है मान लिया गया कि कंपाइलर एक ब्लैक बॉक्स के रूप में माना जाएगा), लेकिन यह कमियों को ठीक नहीं करता है volatile
जलेफ

15
@ जैलफ: आर्क रॉबिन्सन (इस पृष्ठ पर अन्य जगहों से जुड़ा हुआ), 10 वीं टिप्पणी ("स्पड" द्वारा) लेख देखें। मूल रूप से, reordering कोड का तर्क नहीं बदलता है। पोस्ट किया गया कोड किसी कार्य को रद्द करने के लिए ध्वज का उपयोग करता है (कार्य को पूरा करने के लिए संकेत देने के बजाय), इसलिए यह कोई फर्क नहीं पड़ता कि कोड से पहले या बाद में कार्य रद्द हो गया है (जैसे: while (work_left) { do_piece_of_work(); if (cancel) break;}यदि रद्द लूप के भीतर फिर से चालू हो गया है,) तर्क अभी भी मान्य है। मेरे पास कोड का एक टुकड़ा था जो समान रूप से काम करता था: यदि मुख्य धागा समाप्त करना चाहता है, तो यह अन्य थ्रेड्स के लिए ध्वज सेट करता है, लेकिन यह नहीं ...

15
... कोई बात नहीं अगर अन्य धागे अपने कार्य छोरों की एक अतिरिक्त कुछ पुनरावृत्तियों को समाप्त करने से पहले करते हैं, जब तक कि यह झंडा सेट होने के तुरंत बाद यथोचित होता है। बेशक, यह केवल वह उपयोग है जिसके बारे में मैं सोच सकता हूँ और इसके बजाय आला (और उन प्लेटफार्मों पर काम नहीं कर सकता है जहां एक अस्थिर चर को लिखने से अन्य थ्रेड्स में परिवर्तन दिखाई नहीं देता है, हालांकि कम से कम x86 और x86-64 पर यह काम करता है)। मैं निश्चित रूप से किसी को भी वास्तव में ऐसा करने की सलाह नहीं दूंगा, बिना किसी बहुत अच्छे कारण के, मैं सिर्फ इतना कह रहा हूं कि "अस्थिरता जैसा गुणक कभी भी बहुआयामी कोड में उपयोगी नहीं है" 100% सही नहीं है।

15

C ++ 11 में, आम तौर पर volatileथ्रेडिंग के लिए उपयोग नहीं किया जाता है , केवल MMIO के लिए

लेकिन टीएल: डीआर, यह mo_relaxedसुसंगत कैश (यानी सब कुछ) के साथ हार्डवेयर पर परमाणु की तरह "काम" करता है ; यह रजिस्टरों में var रखते हुए संकलक को रोकने के लिए पर्याप्त है। atomicएटमॉसिटी या इंटर-थ्रू दृश्यता बनाने के लिए मेमोरी बैरियर की आवश्यकता नहीं होती है, केवल ऑपरेशन के पहले / उसके बाद प्रतीक्षा करने के लिए अलग-अलग वेरिएबल्स में इस थ्रेड के एक्सेस के बीच ऑर्डर बनाने के लिए। mo_relaxedकभी किसी बाधा की जरूरत नहीं है, बस लोड, स्टोर, या आरएमडब्ल्यू।

C ++ 11 से पहले बुरे पुराने दिनों मेंvolatile (और बाधाओं के लिए इनलाइन- asm) के साथ रोल-ही-एटोमिक्स , कुछ चीजों को काम करने का एकमात्र अच्छा तरीका था । लेकिन यह बहुत सारी मान्यताओं पर निर्भर करता है कि कार्यान्वयन कैसे काम करता है और किसी भी मानक द्वारा कभी इसकी गारंटी नहीं दी जाती है।std::atomicvolatile

उदाहरण के लिए, लिनक्स कर्नेल अभी भी अपने स्वयं के हाथ से लुढ़का एटोमिक्स का उपयोग करता है volatile, लेकिन केवल कुछ विशिष्ट सी कार्यान्वयन (GNU C, क्लैंग और शायद ICC) का समर्थन करता है। आंशिक रूप से ऐसा इसलिए है क्योंकि GNU C एक्सटेंशन और इनलाइन as वाक्यविन्यास और शब्दार्थ, लेकिन यह भी क्योंकि यह कंपाइलर कैसे काम करता है, इसके बारे में कुछ मान्यताओं पर निर्भर करता है।

यह नई परियोजनाओं के लिए लगभग हमेशा गलत विकल्प है; आप उपयोग कर सकते हैं std::atomic(के साथ std::memory_order_relaxed) एक संकलक प्राप्त करने के लिए उसी कुशल मशीन कोड का उपयोग करें जिसे आप कर सकते हैं volatileथ्रेडिंग उद्देश्यों के लिए obsoletes के std::atomicसाथ । mo_relaxedvolatile(शायद कुछ कंपाइलरों के साथ छूटे हुए अनुकूलन के आसपास कामatomic<double> करने के अलावा ।)

std::atomicमुख्यधारा के संकलक (जैसे जीसीसी और क्लैंग) पर आंतरिक कार्यान्वयन केवल आंतरिक रूप से उपयोग नहीं करता है volatile; संकलक सीधे परमाणु भार, स्टोर और आरएमडब्ल्यू बिलिन कार्यों को उजागर करते हैं। (उदाहरण के लिए GNU C __atomicबिल्डिंग्स जो "सादे" ऑब्जेक्ट पर काम करते हैं।)


अस्थिर व्यवहार में प्रयोग करने योग्य है (लेकिन ऐसा न करें)

कहा कि, वास्तविक सीपीयू पर मौजूदा C ++ क्रियान्वयन volatileजैसी चीज़ों के लिए व्यवहार में प्रयोग करने योग्य है exit_now, क्योंकि सीपीयू कैसे काम करते हैं (सुसंगत कैश) और साझा मान्यताओं के बारे में कैसे volatileकाम करना चाहिए। लेकिन बहुत अधिक नहीं, और अनुशंसित नहीं हैइस उत्तर का उद्देश्य यह बताना है कि मौजूदा सीपीयू और सी ++ कार्यान्वयन वास्तव में कैसे काम करते हैं। अगर आपको इस बात की कोई परवाह नहीं है, तो आपको बस इतना पता होना चाहिए कि थ्रेडिंग के लिए std::atomicmo_relaxed obsoletes volatileहै।

(आईएसओ सी ++ मानक इस पर बहुत अस्पष्ट है, बस कह रही है कि volatileएक्सेस को सी ++ एब्सट्रैक्ट मशीन के नियमों के अनुसार कड़ाई से मूल्यांकन किया जाना चाहिए, अनुकूलित नहीं है। यह देखते हुए कि वास्तविक कार्यान्वयन मशीन के मेमोरी एड्रेस-स्पेस का उपयोग C ++ एरो स्पेस के लिए करते हैं। इसका मतलब यह है कि volatileरीड और असाइनमेंट को ऑब्जेक्ट-प्रतिनिधित्व को मेमोरी में एक्सेस करने के लिए निर्देशों को लोड / स्टोर करने के लिए संकलित करना है।)


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

    // global
    bool exit_now = false;

    // in one thread
    while (!exit_now) { do_stuff; }

    // in another thread, or signal handler in this thread
    exit_now = true;

बिना अस्थिर या परमाणु, के रूप में करता है, तो नियम और कोई डेटा-दौड़ यूबी की धारणा एएसएम में यह एक बार अनुकूलन करने के लिए है कि केवल चेक के ध्वज एक संकलक की अनुमति देता है , में प्रवेश (या नहीं) अनंत लूप से पहले। वास्तविक संकलक के लिए वास्तविक जीवन में ऐसा ही होता है। (और आमतौर पर do_stuffलूप से बाहर निकलने के कारण आमतौर पर बहुत अधिक अनुकूलन करते हैं, इसलिए किसी भी बाद के कोड ने परिणाम का उपयोग किया हो सकता है अगर हम लूप में प्रवेश नहीं करते हैं)।

 // Optimizing compilers transform the loop into asm like this
    if (!exit_now) {        // check once before entering loop
        while(1) do_stuff;  // infinite loop
    }

मल्टीथ्रेडिंग प्रोग्राम अनुकूलित मोड में अटका हुआ है, लेकिन सामान्य रूप से चलता है -O0 एक उदाहरण है (जीसीसी के एसएसएम आउटपुट के विवरण के साथ) यह वास्तव में x86-64 पर जीसीसी के साथ कैसे होता है। इसके अलावा MCU प्रोग्रामिंग - C ++ O2 ऑप्टिमाइज़ेशन टूट जाता है जबकि इलेक्ट्रॉनिक्स पर लूप । एक और उदाहरण दिखाता है।

हम आम तौर पर आक्रामक अनुकूलन चाहते हैं कि सीएसई और लहरा लूप से बाहर निकलता है, जिसमें वैश्विक चर शामिल हैं।

C ++ 11 से पहले,volatile bool exit_now इस काम को सामान्य (सामान्य C ++ कार्यान्वयन पर) करने का एक तरीका था । लेकिन C ++ 11 में, डेटा-रेस UB अभी भी लागू होता है, volatileइसलिए यह वास्तव में आईएसओ मानक द्वारा हर जगह काम करने की गारंटी नहीं है, यहां तक ​​कि एचडब्ल्यू सुसंगत कैश भी।

ध्यान दें कि व्यापक प्रकारों के लिए, volatileफाड़ने की कमी की कोई गारंटी नहीं देता है। मैंने उस अंतर को यहाँ अनदेखा कर दिया boolक्योंकि यह सामान्य कार्यान्वयन पर एक गैर-मुद्दा है। लेकिन इसका एक हिस्सा यह भी है कि volatileवह अभी भी आराम करने वाले परमाणु के बराबर डेटा-रेस यूबी के अधीन है।

ध्यान दें कि "जैसा कि इरादा था" का मतलब यह नहीं है कि exit_nowवास्तव में बाहर निकलने के लिए दूसरे धागे की प्रतीक्षा कर रहा है। या यह भी कि exit_now=trueइस धागे में बाद में परिचालन जारी रखने से पहले यह वाष्पशील स्टोर का इंतजार कर रहा है । ( atomic<bool>डिफ़ॉल्ट के साथ mo_seq_cstइसे कम से कम seq_cst लोड होने से पहले प्रतीक्षा करना होगा। कई ISAs पर आपको स्टोर के बाद पूर्ण अवरोध मिलेगा)।

C ++ 11 एक गैर-यूबी तरीका प्रदान करता है जो समान संकलन करता है

एक "चलते रहो" या "अब बाहर निकलें" झंडे के std::atomic<bool> flagसाथ उपयोग करना चाहिएmo_relaxed

का उपयोग करते हुए

  • flag.store(true, std::memory_order_relaxed)
  • while( !flag.load(std::memory_order_relaxed) ) { ... }

आपको ठीक वही asm (बिना किसी महंगी बाधा निर्देश के) देगा जो आपको मिलेगा volatile flag

साथ ही नो-फाड़, atomicआपको एक थ्रेड में स्टोर करने और यूबी के बिना दूसरे में लोड करने की क्षमता भी देता है, इसलिए कंपाइलर लोड को लूप से बाहर नहीं फहरा सकता है। (कोई डेटा-रेस यूबी की धारणा यह है कि हम गैर-परमाणु गैर-वाष्पशील वस्तुओं के लिए जो आक्रामक अनुकूलन चाहते हैं, वह अनुमति देता है।) यह सुविधा atomic<T>वैसी ही है जैसी volatileशुद्ध भार और शुद्ध भंडार के लिए है।

atomic<T>+=परमाणु आरएमडब्ल्यू परिचालनों में भी बनाते और बनाते हैं (एक अस्थायी, संचालन में परमाणु भार की तुलना में बहुत अधिक महंगा, फिर एक अलग परमाणु स्टोर। यदि आप एक परमाणु आरएमडब्ल्यू नहीं चाहते हैं, तो एक स्थानीय अस्थायी के साथ अपना कोड लिखें)।

seq_cstआपके द्वारा प्राप्त होने वाले डिफ़ॉल्ट ऑर्डर के साथ while(!flag), यह ऑर्डरिंग गारंटी को भी जोड़ता है। गैर-परमाणु एक्सेस और अन्य परमाणु एक्सेस तक।

(सिद्धांत रूप में, आईएसओ सी ++ मानक एटमिक्स के संकलन-समय के अनुकूलन से इंकार नहीं करता है। लेकिन व्यवहारिक संकलक में ऐसा नहीं है क्योंकि जब यह ठीक नहीं होगा, तो इसे नियंत्रित करने का कोई तरीका नहीं है। कुछ मामले ऐसे भी हैं, जहां volatile atomic<T>हो सकता है। परमाणुओं के अनुकूलन पर पर्याप्त नियंत्रण रखें यदि कंपाइलरों ने अनुकूलन किया है, तो अब कम्पाइलर्स के लिए नहीं। देखें कि कंपाइलर्स निरर्थक एसटीडी मर्ज क्यों नहीं करते हैं :: परमाणु लिखते हैं? ध्यान दें कि wg21 / p0062 volatile atomicवर्तमान कोड का उपयोग करने के खिलाफ ऑप्टिमाइज़ेशन को ऑप्टिमाइज़ करने के लिए उपयोग करते हैं । एटोमिक्स।)


volatile वास्तव में वास्तविक सीपीयू पर इसके लिए काम करता है (लेकिन अभी भी इसका उपयोग नहीं करते हैं)

यहां तक ​​कि कमजोर-ऑर्डर किए गए मेमोरी मॉडल (गैर-x86) के साथ भी । लेकिन असल में यह प्रयोग नहीं करते, उपयोग atomic<T>के साथ mo_relaxedबजाय !! इस अनुभाग का उद्देश्य वास्तविक सीपीयू कैसे काम करते हैं, इसके बारे में गलत धारणाओं को संबोधित करना है, औचित्य नहीं volatile। यदि आप लॉकलेस कोड लिख रहे हैं, तो आप शायद प्रदर्शन के बारे में परवाह करते हैं। कैश और अंतर-थ्रेड संचार की लागत को समझना आमतौर पर अच्छे प्रदर्शन के लिए महत्वपूर्ण है।

वास्तविक सीपीयू में सुसंगत कैश / साझा मेमोरी होती है: एक कोर के स्टोर से विश्व स्तर पर दिखाई देने के बाद, कोई अन्य कोर एक स्टोक मूल्य को लोड नहीं कर सकता है । (यह भी देखें मिथक प्रोग्रामर सीपीयू कैश के बारे में विश्वास करते हैं जो जावा वाष्पशील के बारे में कुछ बात करता है, atomic<T>seq_cst मेमोरी ऑर्डर के साथ C ++ के बराबर है ।)

जब मैं लोड कहता हूं , मेरा मतलब है कि एक एसम निर्देश है जो मेमोरी तक पहुंचता है। यह एक volatileपहुंच सुनिश्चित करता है, और गैर-परमाणु / गैर-वाष्पशील C ++ चर के लैवल्यू-टू-रैवल्यू रूपांतरण के समान नहीं है। (जैसे local_tmp = flagया while(!flag))।

केवल एक चीज जिसे आपको हराने की आवश्यकता है, वह संकलन-समय अनुकूलन है जो पहले चेक के बाद बिल्कुल भी लोड नहीं करता है। प्रत्येक पुनरावृत्ति पर कोई भी लोड + चेक पर्याप्त है, बिना किसी आदेश के। इस थ्रेड और मुख्य थ्रेड के बीच सिंक्रनाइज़ेशन के बिना, यह बात करने के लिए सार्थक नहीं है कि वास्तव में स्टोर कब हुआ, या लोड रिट का आदेश दिया गया। लूप में अन्य संचालन। केवल जब यह इस धागे को दिखाई दे रहा है तो यही मायने रखता है। जब आप एग्जिट_वन फ्लैग सेट देखते हैं, तो आप बाहर निकल जाते हैं। एक विशिष्ट x86 Xeon पर अंतर-कोर विलंबता अलग भौतिक कोर के बीच 40ns की तरह कुछ हो सकता है


सिद्धांत रूप में: सुसंगत कैश के बिना हार्डवेयर पर C ++ थ्रेड

मैं किसी भी तरह से इसे दूर से कुशल नहीं देख सकता, केवल शुद्ध आईएसओ सी ++ के साथ प्रोग्रामर को स्रोत कोड में स्पष्ट फ्लश करने की आवश्यकता के बिना।

सिद्धांत रूप में आपके पास एक मशीन पर C ++ कार्यान्वयन हो सकता है जो इस तरह नहीं था, जो अन्य कोर पर अन्य थ्रेड्स को दिखाई देने वाली चीजों को बनाने के लिए संकलक-उत्पन्न स्पष्ट फ्लश की आवश्यकता होती है । (या शायद एक बासी प्रति का उपयोग नहीं करने के लिए पढ़ता है)। C ++ मानक यह असंभव नहीं बनाता है, लेकिन C ++ की मेमोरी मॉडल को सुसंगत साझा-मेमोरी मशीनों पर कुशल होने के लिए डिज़ाइन किया गया है। उदाहरण के लिए, C ++ मानक यहां तक ​​कि "रीड-रीड कोहेरेंस", "राइट-रीड कोहेरेंस" के बारे में बात करता है, आदि मानक में एक नोट भी हार्डवेयर से कनेक्शन को इंगित करता है:

http://eel.is/c++draft/intro.races#19

[नोट: चार पूर्ववर्ती सुसंगतता आवश्यकताओं को प्रभावी ढंग से एक ही वस्तु के लिए परमाणु संचालन के संकलक के पुन: संचालन को अस्वीकार कर देता है, भले ही दोनों ऑपरेशन आराम से लोड हो। यह प्रभावी रूप से C ++ परमाणु संचालन के लिए उपलब्ध अधिकांश हार्डवेयर द्वारा प्रदान की गई कैश सुसंगतता को प्रभावी बनाता है। - अंतिम नोट]

releaseस्टोर के लिए कोई तंत्र नहीं है केवल खुद को और कुछ चुनिंदा पता-रेंजों को फ्लश करने के लिए: यह सब कुछ सिंक करना होगा क्योंकि यह नहीं पता होगा कि अन्य धागे क्या पढ़ना चाहते हैं यदि उनके अधिग्रहण-लोड ने इस रिलीज-स्टोर को देखा (गठन कर रहे हैं) रिलीज-सीक्वेंस जो कि थ्रेड्स में एक होने से पहले संबंध स्थापित करता है, गारंटी देता है कि राइटिंग थ्रेड द्वारा किए गए पहले गैर-परमाणु संचालन अब पढ़ने के लिए सुरक्षित हैं। जब तक कि यह रिलीज स्टोर के बाद उन्हें आगे नहीं लिखता ...) या कंपाइलर होगा यह साबित करने के लिए वास्तव में स्मार्ट होना चाहिए कि केवल कुछ कैश लाइनों को फ्लशिंग करने की आवश्यकता है।

संबंधित: क्या मेरा उत्तर NUMA पर mov + mfence सुरक्षित है? सुसंगत साझा मेमोरी के बिना x86 सिस्टम के गैर-अस्तित्व के बारे में विस्तार से जाता है। यह भी संबंधित: लोड और स्टोर एआरएम पर लोड / स्टोर के बारे में अधिक उसी स्थान पर पुन : व्यवस्थित करने के लिए ।

वहाँ रहे हैं मैं गैर सुसंगत साझा स्मृति के साथ समूहों लगता है, लेकिन वे एकल प्रणाली की छवि मशीनों नहीं कर रहे हैं। प्रत्येक सुसंगतता डोमेन एक अलग कर्नेल चलाता है, इसलिए आप इसके पार एकल C ++ प्रोग्राम के थ्रेड नहीं चला सकते हैं। इसके बजाय आप कार्यक्रम के अलग-अलग उदाहरण चलाते हैं (प्रत्येक का अपना पता स्थान: एक उदाहरण में संकेत दूसरे में मान्य नहीं हैं)।

उन्हें स्पष्ट फ्लश के माध्यम से एक-दूसरे के साथ संवाद करने के लिए, आप प्रोग्राम को निर्दिष्ट करने के लिए एमपीआई या अन्य संदेश-गुजरने वाले एपीआई का उपयोग करेंगे।


वास्तविक हार्डवेयर std::threadकैश सुसंगतता सीमाओं में नहीं चलता है:

कुछ विषम एआरएम चिप्स साझा भौतिक पता स्थान लेकिन साथ मौजूद हैं, नहीं भीतरी साझा करने योग्य कैश डोमेन। तो सुसंगत नहीं। (उदाहरण टिप्पणी धागा A8 कोर और TI कोरारा AM335x की तरह एक Cortex-M3)।

लेकिन अलग-अलग गुठली उन कोर पर चलेगी, न कि एक एकल प्रणाली की छवि जो दोनों कोर में धागे चला सकती है। मैं किसी भी सी ++ कार्यान्वयन के बारे में नहीं जानता हूं जो std::threadसीपीयू कोर के पार सुसंगत कैश के बिना थ्रेड चलाते हैं।

एआरएम के लिए विशेष रूप से, जीसीसी और क्लैंग जनरेट कोड को मानते हुए सभी धागे एक ही इनर-शेअरबल डोमेन में चलते हैं। वास्तव में, ARMv7 ISA मैनुअल कहता है

यह आर्किटेक्चर (ARMv7) एक उम्मीद के साथ लिखा गया है कि एक ही ऑपरेटिंग सिस्टम या हाइपरविजर का उपयोग करने वाले सभी प्रोसेसर एक ही इनर शेरेबल शैरबिलिटी डोमेन में हैं

इसलिए अलग-अलग डोमेन के बीच गैर-सुसंगत साझा मेमोरी अलग-अलग कर्नेल के तहत विभिन्न प्रक्रियाओं के बीच संचार के लिए साझा मेमोरी क्षेत्रों के स्पष्ट प्रणाली-विशिष्ट उपयोग के लिए केवल एक चीज है।

इस कंपाइलर में कोड-जीन dmb ish(इनर शेअरबल बैरियर) बनाम dmb sy(सिस्टम) मेमोरी बैरियर्स के बारे में इस CoreCLR चर्चा को भी देखें ।

मैं यह दावा करता हूं कि std::threadगैर-सुसंगत कैश के साथ कोर के पार किसी भी अन्य आईएसए के लिए कोई सी ++ कार्यान्वयन नहीं है । मेरे पास यह सबूत नहीं है कि ऐसा कोई कार्यान्वयन मौजूद नहीं है, लेकिन यह अत्यधिक संभावना नहीं है। जब तक आप उस तरीके से काम करने वाले एचडब्ल्यू के एक विशिष्ट विदेशी टुकड़े को लक्षित नहीं कर रहे हैं, प्रदर्शन के बारे में आपकी सोच को सभी थ्रेड्स के बीच MESI की तरह कैश सुसंगतता माननी चाहिए। (अधिमानतः का उपयोग atomic<T>मायनों में कि गारंटी देता है शुद्धता, हालांकि!)


सुसंगत कैश इसे सरल बनाता है

लेकिन सुसंगत कैश, एक रिलीज की दुकान को लागू करने के साथ एक मल्टी कोर सिस्टम पर सिर्फ आदेश इस सूत्र के भंडार के लिए कैश में प्रतिबद्ध हैं, किसी भी स्पष्ट फ्लशिंग नहीं कर रही है। ( https://preshing.com/20120913/acquire-and-release-semantics/ और https://preshing.com/20120710/memory-barriers-are-like-source-control-operations/ )। (और एक अधिग्रहण-लोड का मतलब दूसरे कोर में कैश तक पहुंच का आदेश देना है)।

एक मेमोरी बैरियर इंस्ट्रक्शन सिर्फ वर्तमान थ्रेड के लोड और / या स्टोर को ब्लॉक करता है जब तक कि स्टोर बफर नालियों; यह हमेशा अपने दम पर संभव के रूप में तेजी से होता है। ( क्या मेमोरी बैरियर यह सुनिश्चित करता है कि कैश सुसंगतता पूरी हो गई है? इस गलत धारणा को संबोधित करता है)। इसलिए यदि आपको ऑर्डर देने की आवश्यकता नहीं है, तो बस दूसरे थ्रेड्स में दृश्यता का संकेत दें, mo_relaxedठीक है। (और ऐसा है volatile, लेकिन ऐसा मत करो।)

प्रोसेसर को C / C ++ 11 मैपिंग भी देखें

मजेदार तथ्य: x86 पर, प्रत्येक एएसएम स्टोर एक रिलीज़-स्टोर है क्योंकि x86 मेमोरी मॉडल मूल रूप से seq-cst plus a store बफर (स्टोर फ़ॉरवर्डिंग के साथ) है।


अर्ध-संबंधित फिर से: स्टोर बफर, वैश्विक दृश्यता, और सुसंगतता: सी ++ 11 बहुत कम गारंटी देता है। अधिकांश वास्तविक आईएसएएस (पावरपीसी को छोड़कर) गारंटी देते हैं कि सभी धागे दो स्टोरों की उपस्थिति के आदेश पर दो अन्य धागे से सहमत हो सकते हैं। (औपचारिक कंप्यूटर-आर्किटेक्चर मेमोरी मॉडल शब्दावली में, वे "मल्टी-कॉपी परमाणु" हैं)।

एक और गलत धारणा है कि स्मृति बाड़ एएसएम निर्देश दुकान बफर फ्लश करने के लिए अन्य कोर हमारी दुकानों को देखने के लिए के लिए आवश्यक हैं है सब पर । वास्तव में स्टोर बफर हमेशा (एल 1 डी कैश के लिए) के रूप में उपवास के रूप में संभव के रूप में तेजी से करने की कोशिश कर रहा है, अन्यथा यह भर जाएगा और स्टाल निष्पादन। एक पूर्ण अवरोध / बाड़ क्या करता है वर्तमान थ्रेड को स्टोर बफर तक सूखा दिया जाता है , इसलिए हमारे बाद के भार हमारे पहले के स्टोरों के बाद वैश्विक क्रम में दिखाई देते हैं।

(x86 का जोरदार आदेश दिया गया asm मेमोरी मॉडल का अर्थ है कि volatilex86 पर आप को पास देना बंद हो सकता है mo_acq_rel, सिवाय इसके कि गैर-परमाणु चर के साथ संकलित समय पुनरावृत्ति अभी भी हो सकती है। लेकिन अधिकांश गैर- x86 में कमजोर रूप से स्मृति वाले मॉडल हैं volatileऔर relaxedलगभग उतने ही हैं। कमजोर की mo_relaxedअनुमति देता है।)


टिप्पणियाँ विस्तारित चर्चा के लिए नहीं हैं; इस वार्तालाप को बातचीत में स्थानांतरित कर दिया गया है ।
शमूएल ल्यू

2
महान लेखन। यह ठीक वही है जो मैं ( सभी तथ्यों को देते हुए) एक कंबल बयान के बजाय कह रहा था कि "एक ही वैश्विक साझा बूलियन ध्वज के लिए अस्थिर के बजाय परमाणु का उपयोग करें"।
बर्नी

2
@bernie: मैंने इसे दोहराया दावों से निराश होने के बाद लिखा था कि उपयोग नहीं करने से कैश मेंatomic एक ही चर के लिए अलग-अलग मान हो सकते हैं । / facepalm। कैश में, नहीं, सीपीयू में पंजीकृत है हाँ (गैर-परमाणु चर के साथ); सीपीयू सुसंगत कैश का उपयोग करते हैं। मैं चाहता हूं कि एसओ पर अन्य प्रश्न सीपीयू के काम करने के तरीके के बारे में गलतफहमी फैलाने के लिए स्पष्टीकरण से भरे नहीं थे । (क्योंकि प्रदर्शन के कारणों को समझने के लिए यह एक उपयोगी बात है, और यह समझाने में भी मदद करता है कि आईएसओ सी ++ परमाणु नियम क्यों लिखे गए हैं।)atomic
पीटर कॉर्ड्स

-1
#include <iostream>
#include <thread>
#include <unistd.h>
using namespace std;

bool checkValue = false;

int main()
{
    std::thread writer([&](){
            sleep(2);
            checkValue = true;
            std::cout << "Value of checkValue set to " << checkValue << std::endl;
        });

    std::thread reader([&](){
            while(!checkValue);
        });

    writer.join();
    reader.join();
}

एक बार एक साक्षात्कारकर्ता जो यह भी मानता था कि अस्थिरता मेरे साथ यह तर्क देती है कि ऑप्टिमाइज़ेशन किसी भी समस्या का कारण नहीं होगा और अलग-अलग कोर की अलग-अलग कैश लाइनों का उल्लेख कर रहा था और यह सब (वास्तव में वह क्या संदर्भित कर रहा था यह नहीं समझ पाया)। लेकिन कोड का यह टुकड़ा जब जी ++ (जी ++ -ओ 3 थ्रेड.कैप -थ्र्रेड) पर संकलित होता है, तो यह अपरिभाषित व्यवहार दिखाता है। मूल रूप से यदि मान ठीक से जाँचने से पहले सेट हो जाता है तो यह ठीक काम करता है और यदि यह मूल्य प्राप्त करने के लिए परेशान किए बिना लूप में जाता है (जो वास्तव में दूसरे धागे से बदल गया था)। मूल रूप से मेरा मानना ​​है कि चेकवैल्यू का मूल्य केवल रजिस्टर में एक बार मिलता है और कभी भी उच्चतम स्तर के अनुकूलन के तहत दोबारा चेक नहीं किया जाता है। यदि भ्रूण से पहले इसका सेट सही है, तो यह ठीक काम करता है और यदि यह लूप में नहीं जाता है। कृपया गलत होने पर मुझे सुधारें।


4
इससे क्या लेना-देना है volatile? हां, यह कोड यूबी है - लेकिन यह यूबी के साथ volatileभी है।
डेविड श्वार्ट्ज

-2

आपको अस्थिर और संभवतः लॉकिंग की आवश्यकता है।

वाष्पशील ऑप्टिमाइज़र को बताता है कि मूल्य अतुल्यकालिक रूप से बदल सकता है

volatile bool flag = false;

while (!flag) {
    /*do something*/
}

लूप के चारों ओर हर बार झंडा पढ़ेगा।

यदि आप ऑप्टिमाइज़ेशन को बंद कर देते हैं या हर वैरिएबल को अस्थिर कर देते हैं तो एक प्रोग्राम समान लेकिन धीमा व्यवहार करेगा। वाष्पशील का अर्थ है 'मैं जानता हूं कि आपने शायद इसे पढ़ लिया है और जानते हैं कि यह क्या कहता है, लेकिन अगर मैं कहता हूं कि इसे पढ़ें तो इसे पढ़ें।

ताला लगाना कार्यक्रम का एक हिस्सा है। तो, वैसे, यदि आप सेमाफोर को लागू कर रहे हैं, तो अन्य चीजों के बीच उन्हें अस्थिर होना चाहिए। (यह कोशिश मत करो, यह कठिन है, शायद थोड़ा असेंबलर या नए परमाणु सामान की आवश्यकता होगी, और यह पहले ही हो चुका है।)


1
लेकिन यह नहीं है, और अन्य प्रतिक्रिया में एक ही उदाहरण, व्यस्त प्रतीक्षा और इस तरह कुछ है कि बचा जाना चाहिए? यदि यह एक विरोधाभासी उदाहरण है, तो क्या कोई वास्तविक जीवन उदाहरण हैं जो कि नहीं हैं?
डेविड प्रेस्टन

7
@ क्रिस: व्यस्त प्रतीक्षा कभी-कभी एक अच्छा समाधान है। विशेष रूप से, यदि आप केवल कुछ घड़ी चक्रों के लिए प्रतीक्षा करने की अपेक्षा करते हैं, तो यह थ्रेड को निलंबित करने के बहुत अधिक हैवीवेट दृष्टिकोण की तुलना में बहुत कम ओवरहेड करता है। बेशक, जैसा कि मैंने अन्य टिप्पणियों में उल्लेख किया है, उदाहरण जैसे कि यह एक त्रुटिपूर्ण है क्योंकि वे मानते हैं कि ध्वज को पढ़ना / लिखना उस कोड के संबंध में पुन: व्यवस्थित नहीं किया जाएगा जो इसे बचाता है, और इस तरह की कोई गारंटी नहीं दी जाती है, और इसलिए , volatileयहां तक कि इस मामले में वास्तव में उपयोगी नहीं है। लेकिन व्यस्त प्रतीक्षा एक कभी-कभी उपयोगी तकनीक है।
जालफ

3
@richard हाँ और नहीं। पहली छमाही सही है। लेकिन इसका मतलब केवल यह है कि सीपीयू और कंपाइलर को एक दूसरे के संबंध में अस्थिर चर को फिर से चालू करने की अनुमति नहीं है। यदि मैं एक अस्थिर चर A को पढ़ता हूं, और फिर एक अस्थिर चर B को पढ़ता हूं, तो कंपाइलर को बी से पहले A को पढ़ने के लिए (यहां तक ​​कि सीपीयू रीक्रोडिंग के साथ) गारंटी देने वाले कोड का उत्सर्जन करना चाहिए, लेकिन यह सभी गैर-वाष्पशील चर एक्सेस के बारे में कोई गारंटी नहीं देता है । उन्हें आपके वाष्पशील पढ़ने / लिखने के चारों ओर फिर से ठीक किया जा सकता है। इसलिए जब तक आप अपने प्रोग्राम में हर वेरिएबल को वाष्पशील नहीं बनाते हैं , यह आपको वह गारंटी नहीं देगा, जिसकी आप रुचि रखते हैं
jalf

2
@ ctrl-alt-delor: यह वह नहीं है जो volatile"नो रीडरिंग " का अर्थ है। आप उम्मीद कर रहे हैं कि इसका मतलब है कि स्टोर प्रोग्राम क्रम में विश्व स्तर पर (अन्य थ्रेड्स के लिए) दिखाई देंगे । यही आपके atomic<T>साथ है memory_order_releaseया seq_cstदेता है। लेकिन volatile केवल आपको कोई संकलन-समय पुन: व्यवस्थित करने की गारंटी नहीं देता है : प्रत्येक पहुंच कार्यक्रम क्रम में asm में दिखाई देगी। डिवाइस ड्राइवर के लिए उपयोगी है। और वर्तमान कोर / धागे पर एक बाधा हैंडलर, डीबगर या सिग्नल हैंडलर के साथ बातचीत के लिए उपयोगी है, लेकिन अन्य कोर के साथ बातचीत के लिए नहीं।
पीटर कॉर्ड्स

1
volatileव्यवहार में keep_running, आप यहाँ क्या कर रहे हैं जैसे एक झंडे की जाँच करने के लिए पर्याप्त है: वास्तविक सीपीयू में हमेशा सुसंगत कैश होते हैं जिन्हें मैनुअल फ्लशिंग की आवश्यकता नहीं होती है। लेकिन वहाँ की सिफारिश करने का कोई कारण नहीं volatileसे अधिक atomic<T>के साथ mo_relaxed; आपको वही मिलेगा।
पीटर कॉर्ड्स
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.