2016-01-31 13 views
9

क्या समान स्मृति स्थान पर परमाणु और गैर-परमाणु ओप करना संभव है?सी 11/सी ++ 11 में, उसी स्मृति पर परमाणु/गैर-परमाणु ओप मिश्रण करने के लिए संभव है?

मैं नहीं पूछता क्योंकि मैं वास्तव में ऐसा करना चाहता हूं, लेकिन क्योंकि मैं सी 11/सी ++ 11 मेमोरी मॉडल को समझने की कोशिश कर रहा हूं। वे इतने की तरह एक "डेटा दौड़" परिभाषित करें

एक कार्यक्रम के निष्पादन करता है, तो यह अलग धागे में दो परस्पर विरोधी कार्यों, जिनमें से कम से कम एक परमाणु नहीं होता है एक डेटा दौड़ शामिल है, और न दूसरे से पहले होता है। ऐसी कोई भी डेटा रेस अपरिभाषित व्यवहार में परिणाम देती है। - C11 §5.1.2.4 P25, सी ++ 11 § 1.10 p21

इसकी "जिनमें से कम से कम एक परमाणु नहीं है" बात यह है कि मुझे परेशान कर रहा है। यदि परमाणु और गैर-परमाणु ओप मिश्रण करना संभव नहीं था, तो यह केवल "उस वस्तु पर होगा जो परमाणु नहीं है।"

मैं परमाणु चर पर गैर-परमाणु संचालन करने का कोई सीधा तरीका नहीं देख सकता। सी ++ में std::atomic<T> गैर-परमाणु अर्थशास्त्र के साथ किसी भी परिचालन को परिभाषित नहीं करता है। सी में, परमाणु चर के सभी प्रत्यक्ष पढ़ने/लिखने परमाणु संचालन में अनुवाद किया जाता है।

मुझे लगता है कि memcpy() और अन्य प्रत्यक्ष मेमोरी ऑपरेशन एक परमाणु चर पर एक गैर-परमाणु पढ़ने/लिखने का एक तरीका हो सकता है? अर्थात। memcpy(&atomicvar, othermem, sizeof(atomicvar))? लेकिन क्या यह भी परिभाषित व्यवहार है? सी ++ में, std::atomic कॉपी करने योग्य नहीं है, तो क्या इसे memcpy() पर सी या सी ++ में परिभाषित किया जाएगा?

परमाणु चर (प्रारंभिक या atomic_init() के माध्यम से) पर प्रारंभिक परमाणु होने के लिए परिभाषित किया गया है। लेकिन यह एक बार का ऑपरेशन है: आपको दूसरी बार परमाणु चर प्रारंभ करने की अनुमति नहीं है। प्लेसमेंट नया या एक स्पष्ट विनाशक कॉल भी परमाणु नहीं होगा। लेकिन इन सभी मामलों में, ऐसा प्रतीत नहीं होता है कि यह एक समवर्ती परमाणु ऑपरेशन करने के लिए वैसे भी परिभाषित व्यवहार होगा जो एक प्रारंभिक मूल्य पर परिचालन कर सकता है।

गैर-परमाणु चर पर परमाणु संचालन निष्पादित करना पूरी तरह से असंभव प्रतीत होता है: न तो सी और न ही सी ++ किसी परमाणु कार्यों को परिभाषित करता है जो गैर-परमाणु चर पर काम कर सकते हैं।

तो यहां कहानी क्या है? क्या यह वास्तव में memcpy(), या प्रारंभिक/विनाश, या कुछ और है?

+0

विनाशक का आह्वान करने के बारे में कैसे? – 5gon12eder

+0

memcpy के बारे में कुछ भी परमाणु नहीं है। – Jeff

+1

सी 11 परमाणुओं की आपकी विशेषता http: //en.cppreference.com/w/c/atomic के अनुसार गलत है ... – Jeff

उत्तर

1

मुझे लगता है कि आप एक और मामला, रिवर्स ऑर्डर देख रहे हैं। प्रारंभिक int पर विचार करें जिसका भंडारण std::atomic_int बनाने के लिए पुन: उपयोग किया जाता है। सभी परमाणु संचालन इसके सीटीआर खत्म होने के बाद होता है, और इसलिए प्रारंभिक स्मृति पर। लेकिन अब-ओवरराइट int पर किसी भी समवर्ती, गैर-परमाणु पहुंच को भी प्रतिबंधित किया जाना चाहिए।

(मैं यहाँ यह सोचते हैं रहा है कि भंडारण जीवन भर के लिए पर्याप्त है और कोई भूमिका निभाता है)

मैं पूरी तरह यकीन है कि क्योंकि मुझे लगता है कि int से पीछे नहीं पहुँच वैसे भी अवैध हो जाएगा तक पहुँचने का प्रकार के रूप में नहीं कर रहा हूँ अभिव्यक्ति int उस समय ऑब्जेक्ट के प्रकार से मेल नहीं खाती (std::atomic<int>)। हालांकि, " पर ऑब्जेक्ट का प्रकार " एक सिंगल रैखिक समय प्रगति मानता है जो बहु-थ्रेडेड वातावरण में नहीं है। सी ++ 11 सामान्य रूप से " वैश्विक स्थिति" के बारे में ऐसी धारणाओं को हल करके हल किया गया है, जो अनिश्चित व्यवहार प्रति है, और उस ढांचे में प्रश्न से नियम लागू होता है।

तो शायद रीफ्रिसिंग: यदि एक मेमोरी स्थान पर परमाणु वस्तु के साथ-साथ एक गैर-परमाणु वस्तु होती है, और यदि सबसे पुरानी बनाई गई (पुरानी) वस्तु का विनाश अनुक्रमित नहीं होता है - दूसरे के निर्माण से पहले (नया) ऑब्जेक्ट, तब तक पुराने ऑब्जेक्ट टकराव तक पहुंच को नए ऑब्जेक्ट तक पहुंच के साथ एक्सेस करें जब तक कि पूर्व निर्धारित नहीं होता है।

+0

दिलचस्प सिद्धांत। मुझे यकीन नहीं है कि मैं इसे खरीदता हूं - यह विश्वास करना मुश्किल है कि दो अलग-अलग वस्तुओं के विचार दोनों प्रकार के श्राउडिंगर भावना में एक ही स्मृति में मौजूद हैं, संभवतः परिभाषित व्यवहार माना जा सकता है, जैसे कि यह अतिरिक्त विशिष्टता इसे "डेटा रेस" की परिभाषा अपरिभाषित करने के लिए आवश्यक है। –

+0

@ जोश हैबरमैन: ठीक है, आपको इसे अपरिभाषित करने के लिए एक नियम की आवश्यकता है। सामान्य नियम यह है कि दो स्वतंत्र धागे की अपनी समय-सारिणी होती है, और प्रत्येक टाइमलाइन पर घटनाएं केवल उसी समयरेखा पर अन्य घटनाओं के सापेक्ष अनुक्रमित होती हैं। – MSalters

+0

इस पर कुछ और प्रतिबिंबित करने के बाद, यह सबसे व्यावहारिक उत्तर की तरह लगता है। यह "atomic_init()' परमाणु "उत्तर नहीं है, लेकिन अधिक सामान्य है। अगर हम मानते हैं कि ऑब्जेक्ट आजीवन शुरुआत और समापन परमाणु नहीं है, तो यह समझ में आता है कि आपको इसके लिए "पहले होता है" सुनिश्चित करने की आवश्यकता है। –

0

अस्वीकरण: मैं समांतरता गुरु नहीं हूं।

क्या समान स्मृति पर परमाणु/गैर-परमाणु ओप मिश्रण करना संभव है, और यदि तो, कैसे?

आप इसे कोड में लिख सकते हैं और संकलित कर सकते हैं, लेकिन यह शायद अपरिभाषित व्यवहार उत्पन्न करेगा।

परमाणुओं के बारे में बात करते समय, यह समझना महत्वपूर्ण है कि वे किस प्रकार की समस्याएं हल करते हैं।

जैसा कि आप जानते हैं, हम जल्द ही "मेमोरी" में जो कॉल करते हैं, वह बहु-स्तरित इकाइयों का सेट है जो स्मृति को पकड़ने में सक्षम हैं।
पहले हमारे पास रैम है, फिर कैश लाइनें, फिर रजिस्टर्स।

मोनो-कोर प्रोसेसर पर, हमारे पास कोई सिंक्रनाइज़ेशन समस्या नहीं है। बहु-कोर प्रोसेसर पर हमारे पास सभी हैं। प्रत्येक कोर में यह रजिस्टरों और कैश लाइनों का अपना सेट होता है।

इससे कुछ समस्याएं आती हैं।

उनमें से पहला मेमोरी रीडरिंग है - सीपीयू कोड को तेजी से चलाने के लिए कुछ पढ़ने/लिखने के निर्देशों को खराब करने के लिए रनटाइम पर निर्णय ले सकता है। यह कुछ अजीब परिणाम उत्पन्न कर सकता है जो उच्च स्तर के कोड पर पूरी तरह से अदृश्य हैं जो निर्देश के इस सेट को लाया।
इस phenomanon का सबसे उत्कृष्ट उदाहरण "दो धागे - दो पूर्णांक" है उदाहरण:

int i=0; 
int j=0; 
thread a -> i=1, then print j 
thread b -> j=1 then print i; 

तार्किक, परिणाम "00" नहीं हो सकता। या तो पहले एक सिरों, परिणाम "01" हो सकता है, या तो बी पहले समाप्त होता है, परिणाम "10" हो सकता है। यदि दोनों एक ही समय में समाप्त होते हैं, तो परिणाम "11" हो सकता है। फिर भी, यदि आप इस कार्यक्रम को अनुकरण करते हैं और इसे लूप में चलाते हैं, तो बहुत ही अच्छी तरह से आप परिणाम देखेंगे "00"

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

उदाहरण के लिए

, इस छद्म कोड को देखो:

bool b = true; 
while (b) -> print 'a' 
new thread -> sleep 4 seconds -> b=false; 

चरित्र 'एक', infinitly मुद्रित किया जा सकता है क्योंकि b कैश की जा सकती है और अद्यतन किया जा कभी नहीं।

paralelism से निपटने के दौरान कई और समस्याएं हैं। (के बारे में स्मृति आदेश पढ़ें)

एटोमिक्स इन से मुद्दों की तरह (संक्षेप में) संकलक/सीपीयू बता कैसे रैम से सही ढंग से अन-चाहता था scrumbling कर के बिना पढ़ सकते हैं और करने के लिए/डेटा लिखने के लिए हल करती है। एक मेमोरी ऑर्डर सीपीयू को इसके मूल्यों को रैम पर लिखने के लिए मजबूर कर सकता है, या रैम से वैल्यूज पढ़ सकता है भले ही वे कैश किए जाएं।

तो, हालांकि आप परमाणुओं के साथ गैर परमाणु क्रियाओं को मिश्रित कर सकते हैं, आप केवल नौकरी का हिस्सा कर रहे हैं।

उदाहरण के लिए की दूसरी उदाहरण के लिए वापस जाने दिया:

atomic bool b = true; 
while (reload b) print 'a' 
new thread - > b = (non atomicly) false. 

तो एक हालांकि धागा फिर से और फिर राम से ख का मूल्य फिर से पढ़ा है, लेकिन अन्य धागा false वापस रैम के लिए नहीं लिख सकते हैं ।

तो हालांकि आप इस तरह के संचालन को कोड में मिश्रित कर सकते हैं, यह अनिश्चित व्यवहार उत्पन्न करेगा।

+0

मैं विशेष रूप से परमाणु/गैर-परमाणु मिश्रण के बारे में पूछ रहा हूं जो * अनिश्चित व्यवहार का आह्वान नहीं करता है। मैं प्रस्तुत करता हूं कि यदि सभी मिश्रण अपरिभाषित व्यवहार था, तो "डेटा रेस" की परिभाषा अलग होगी। मेरे प्रश्न में विवरण देखें। –

संबंधित मुद्दे