2009-08-18 18 views
9

जावा में अद्यतन करना, डबल और लम्बे चर को अद्यतन करना परमाणु नहीं हो सकता है, क्योंकि डबल/लंबे दो अलग-अलग 32 बिट्स चर के रूप में माना जा रहा है।डबल ऑपरेशन परमाणु

http://java.sun.com/docs/books/jls/second_edition/html/memory.doc.html#28733

सी ++ में, अगर मैं 32 बिट इंटेल प्रोसेसर + माइक्रोसॉफ्ट विजुअल C++ संकलक उपयोग कर रहा हूँ, डबल अपडेट कर रहा है (8 बाइट) आपरेशन परमाणु?

मुझे इस व्यवहार पर अधिक विशिष्टता का उल्लेख नहीं मिल रहा है।

थ्रेड एक चर एक्स 1 लिखने की कोशिश कर:

जब मैं कहता हूँ "परमाणु चर", यहाँ मैं क्या मतलब है। थ्रेड बी चर 2 के लिए लिखने की कोशिश कर रहा है।

हमें चर x से मान 1 या 2 प्राप्त होगा, लेकिन एक अपरिभाषित मान नहीं है।

+0

हां, 32-बिट x86 (मूल पेंटियम के बाद) में [कुशल हार्डवेयर समर्थन] है (https://stackoverflow.com/questions/36624881/why-is-integer-assignment-on-a- स्वाभाविक रूप से- निर्दिष्ट - उपलब्ध -टॉमिक) लॉक-फ्री 'std :: atomic 'लोड, स्टोर और सीएएस के लिए)। चाहे आपका कंपाइलर कुशल कोड बनाता है या नहीं, एक और मुद्दा है: https://stackoverflow.com/questions/45055402/atomic-double-floating-point-or-sse-avx-vector-load-store-on-x86-64। संरेखित 'डबल' कभी "फाड़ना" नहीं होगा, लेकिन 'std :: atomic ' का उपयोग करना सुरक्षित है। –

उत्तर

8

यह हार्डवेयर विशिष्ट है और एक आर्किटेक्चर पर निर्भर करता है। X86 और x86_64 8 बाइट लिखने या पढ़ने के लिए परमाणु होने की गारंटी दी जाती है, अगर वे गठबंधन होते हैं।

इंटेल 64 स्मृति आदेश देने की गारंटी देता है कि निम्नलिखित स्मृति-निर्देशों पर अभिगमन से प्रत्येक के लिए, घटक स्मृति आपरेशन प्रकट होता है परवाह किए बिना एक भी स्मृति पहुँच के रूप में निष्पादित करने के लिए: इंटेल वास्तुकला मेमोरी श्वेत पत्र आदेश से हवाला देते हुए स्मृति प्रकार:

  1. निर्देश जो एक बाइट को पढ़ते या लिखते हैं।

  2. निर्देश जो एक शब्द (2 बाइट्स) को पढ़ते या लिखते हैं जिनके पते 2 बाइट सीमा पर गठबंधन है।

  3. निर्देश जो एक डबलवर्ड (4 बाइट्स) को पढ़ते या लिखते हैं जिनके पते को 4 बाइट सीमा पर गठबंधन किया गया है।

  4. निर्देश जो एक क्वाडवर्ड (8 बाइट्स) को पढ़ते या लिखते हैं जिनके पते 8 बाइट सीमा पर गठबंधन है।

सभी बंद कर दिया निर्देश (परोक्ष बंद कर दिया xchg शिक्षा और एक ताला उपसर्ग के साथ अन्य -पढ़ने के लिए संशोधित-लिखने निर्देश) एक अविभाज्य और लोड (रों) दुकान के बाद की अबाधित अनुक्रम हैं (रों) स्मृति प्रकार और संरेखण की परवाह किए बिना।

+3

यह कंपाइलर पर भी निर्भर करता है, यह सुनिश्चित करने के लिए आवश्यक नहीं है कि युगल 8 जगह पहले गठबंधन हों, या उन्हें पढ़ने या लिखने के लिए एकल क्वाडवर्ड सेशन का उपयोग करें। यद्यपि आपको लगता है कि यह शायद होगा, और मैं भी दृश्य सी ++ दस्तावेजों की अपेक्षा करता हूं कि यह करता है या नहीं। –

+1

हां, यह संकलक एबीआई में निर्दिष्ट है। गैर-ऑटो चर के लिए युगल हमेशा गठबंधन होते हैं, सिवाय इसके कि अगर स्पष्ट रूप से निर्दिष्ट गैर गठबंधन किया गया हो। 32 बिट सिस्टम में स्टैक पर वेरिएबल के लिए वे असाइन किए जा सकते हैं यदि स्टैक किसी भी तरह से असाइन नहीं हो रहा है, उदाहरण के लिए, बाहरी, गैर-सी प्रोग्राम से एक funcitions कहा जाता है। लेकिन आप किसी भी फ़ंक्शन में स्टैक से वस्तुओं को वापस नहीं करना चाहते हैं ... – hirschhornsalz

+0

आप ऑटोमिक्स नहीं लौटते हैं, लेकिन आप उन्हें कॉल करने वाले फ़ंक्शन में पॉइंटर पास कर सकते हैं। लेकिन मुझे लगता है कि आपने जो कहा है वह प्रश्नकर्ता के लिए पर्याप्त है - जब तक वह नियंत्रित करता है कि उन्हें कैसे परिभाषित किया गया था, तो वह यह सुनिश्चित कर सकता है कि उसके युगल तक पहुंच परमाणु है। –

-2

मैं किसी भी आर्किटेक्चर में नहीं सोचूंगा, थ्रेड/संदर्भ स्विचिंग एक रजिस्टर को आधा रास्ते अपडेट करने में बाधा डालती है ताकि आपको उदाहरण के लिए छोड़ा जा सके 18 बिट्स को अद्यतन करने के लिए यह 32 बिट्स अपडेट किया जा रहा है। स्मृति स्थान अपडेट करने के लिए वही (बशर्ते कि यह मूल पहुंच इकाई है, 8,16,32,64 बिट्स इत्यादि)।

+1

समस्या संदर्भ स्विचिंग नहीं है, यह मल्टीकोर और मल्टीक्यू है। – AProgrammer

+0

मल्टीकोर/बहु सीपीयू आर्किटेक्चर में भी भौतिक मेमोरी एक्सेस को मेमोरी कंट्रोलर द्वारा क्रमबद्ध किया जाना है। यह एक ही समय अवधि में एक ही सर्किट्री तक पहुंचने के लिए विद्युत उपकरणों को असंभव है। मेमोरी कंट्रोलर ब्लॉक में मेमोरी एक्सेस करता है, और डेटा बस चौड़ाई की पूरी इकाइयों में, इसलिए स्मृति स्थान का आंशिक अद्यतन होना संभव नहीं है। – Indy9000

+1

तो क्या दो कैश लाइनों की सीमा के पार डबल है? मुझे संदेह है कि एमएसवीसी ++ ऐसा करेगा, क्योंकि सबकुछ 2 के शक्तियों में इसके आकार के साथ गठबंधन किया जाएगा। लेकिन यदि आप सामान्यीकरण कर रहे हैं, तो यह सी ++ मानक की आवश्यकता नहीं है (और कम से कम एआरएम एबीआई, लम्बे और युगल में केवल 4-गठबंधन होना चाहिए, 8-गठबंधन नहीं)। –

-2

तो क्या इस प्रश्न का उत्तर दिया गया है?मैं एक साधारण परीक्षण कार्यक्रम एक डबल बदलते भाग गया:

 
#include <stdio.h> 

int main(int argc, char** argv) 
{ 
    double i = 3.14159265358979323; 
    i += 84626.433; 
} 

मैं बिना अनुकूलन (जीसीसी -O0) यह संकलित है, और सभी काम के संचालन के इस तरह के fldl .LC0 और faddp %st, %st(1) के रूप में एक कोडांतरक निर्देश के साथ प्रदर्शन कर रहे हैं। (i += 84626.433 निश्चित रूप से दो संचालन किया गया है, faddp और fstpl)।

क्या एक धागा वास्तव में faddp जैसे एक निर्देश के भीतर बाधित हो सकता है?

+0

के भीतर फिट कैश मेमोरी तक पहुंचता है "क्या एक थ्रेड वास्तव में एक ही निर्देश जैसे फडप में बाधित हो सकता है?"। नहीं, थ्रेड को एक ही निर्देश के अंदर "बाधित" नहीं किया जा सकता है, दो सीपीयू एक ही समय में अपने निर्देशों का पालन कर सकते हैं, और एक सीपीयू केवल दूसरे सीपीयू के परिणाम का हिस्सा देख सकता है यदि निर्देश एकल में नहीं किया जाता है बस लेनदेन – Suma

1

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

विज़ुअल सी ++ आदिम प्रकारों को आवंटित करेगा (article देखें) और जब यह गारंटी देनी चाहिए कि स्मृति के लिए लिखते समय यह बिट्स खराब नहीं होंगे (8 बाइट आवंटन हमेशा एक 64 या 128 बिट कैश लाइन में होता है) बाकी पर निर्भर करता है कैसे सीपीयू इसके कैश में गैर-परमाणु डेटा को संभालता है और क्या कैश लाइन को पढ़ने/फ़्लश करने में बाधा डाली जा सकती है। तो यदि आप इंटेल डॉक्स के माध्यम से खोले गए कोर के लिए खोदते हैं और यह आपको गारंटी देता है तो आप जाने के लिए सुरक्षित हैं।

जावा स्पेक इतनी रूढ़िवादी क्यों है कि यह पुराने 386 और कोरि 7 पर उसी तरह से चलने वाला है। जो निश्चित रूप से भ्रमित है लेकिन एक वादा एक वादा है, इसलिए यह कम प्रोमिस करता है :-)

कारण मैं कह रहा हूं कि आपको सीपीयू दस्तावेज़ देखना है कि आपका सीपीयू पुराना 386 हो सकता है, या समान: -)) यह मत भूलना कि 32-बिट CPU पर आपके 8-बाइट ब्लॉक तक पहुंचने के लिए 2 "राउंड" लगते हैं ताकि आप कैश एक्सेस के यांत्रिकी की दया के लिए नीचे आ सकें।

कैश लाइन फ्लशिंग बहुत अधिक डेटा स्थिरता गारंटी देने से इंटेल-इयान गारंटी (स्वचालित कैश स्थिरता) के साथ केवल एक उचित हालिया CPU पर लागू होती है।

+0

32-बिट x86 CPU होने का मतलब यह नहीं है कि सभी आंतरिक डेटा पथ केवल 32-बिट हैं। उदाहरण के लिए, पेंटियम 4 (यहां तक ​​कि शुरुआती 32-बिट-केवल पी 4) अपने एल 1 डी कैश के लिए एक ही पहुंच में 'movaps' 16-बाइट संरेखित लोड करता है। आप एक अच्छा मुद्दा बनाते हैं कि कैश पर परमाणु पहुंच कुल परमाणुता की गारंटी नहीं देता है (उदाहरण के लिए एएमडी के 10 में एक सॉकेट के भीतर परमाणु 16 बी एसएसई लोड/स्टोर हैं, लेकिन कोहेरेंसी प्रोटोकॉल [विभिन्न सॉकेट पर धागे के लिए 8 बी सीमाओं पर फाड़ना] [https : //stackoverflow.com/questions/7646018/sse-instructions-which-cpus-can-do-atomic-16b-memory-operations/7647825#7647825)) –

+0

शुरुआती 386 सिस्टमों में से कुछ में अभी भी 16 हो सकता है -बिटी डेटा बस (और कोई आंतरिक कैश नहीं), तो इसका मतलब होगा कि 'डबल' ने 4 मेमोरी चक्र लिया। वैसे भी, चूंकि आधुनिक एमएसवीसी ++ कोड बनाने वाला नहीं है जो पेंटियम (पी 5) से भी पुराने किसी भी चीज पर चलता है, आपको गारंटी है कि गठबंधन 8 बी लोड/स्टोर परमाणु हैं, भले ही x87 या एसएसई के साथ किया गया हो। (कोई विचार नहीं कि आप कहते हैं कि एफपी कम अनुकूलित है। X86 में वर्षों के लिए उच्च-प्रदर्शन फ्लोटिंग पॉइंट था।) एक बार डेटा कैश तक पहुंचने के बाद, यह याद नहीं करता कि यह कैसा रहा, इसलिए "कैश में गैर-परमाणु डेटा" अजीब है। –

+0

यह * सुरक्षित * यह मानने के लिए है कि 'डबल' अपडेट करना कभी परमाणु नहीं है, लेकिन अत्यधिक रूढ़िवादी है। –

-2

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

+0

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

+0

x86 सुसंगत कैश है। आपको इसके बारे में चिंता करने की ज़रूरत नहीं है। जब तक पाठक वास्तव में स्मृति से पुनः लोड हो जाता है, तो एक मान को पुन: उपयोग करने के बजाय संकलक एक रजिस्टर में रख सकता है, यह अंततः अद्यतन को देखेगा। (यही कारण है कि आपको 'std :: atomic ' का उपयोग करना चाहिए, अब सी ++ 11 मौजूद है। हालांकि वर्तमान कंपाइलर इसके लिए अक्षम कोड बनाते हैं: https://stackoverflow.com/questions/45055402/atomic-double-floating-point -या-एसएसई-एवीएक्स-वेक्टर-लोड-स्टोर-ऑन-x86-64) –

+0

@ एप्रोग्रामर: कोहेन्सी का अर्थ है कि दो कैशों में कैश लाइन के लिए अलग-अलग मान नहीं हो सकते हैं, इसलिए एक बार स्टोर में एल 1 डी कैश के लिए प्रतिबद्ध किया गया है सीपीयू, कोई अन्य सीपीयू एक अलग मूल्य लोड कर सकते हैं। https://en.wikipedia.org/wiki/MESI_protocol। विभिन्न कैश लाइनों में संशोधन के बीच ऑर्डर करना सुसंगत कैश के शीर्ष पर बनाई गई कार्यक्षमता का एक और स्तर है। –

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