2011-03-10 11 views
10

के साथ लिखता है मैं खुद को बहुप्रचारित प्रोग्रामिंग के बारे में एक उलझन में गड़बड़ कर चुका हूं और उम्मीद कर रहा था कि कोई मेरे पास आ सकता है और मुझे कुछ समझ में आ सकता है।परमाणु 64 बिट जीसीसी

काफी पढ़ने के बाद, मुझे समझ में आ गया है कि मुझे 64 बिट सिस्टम पर परमाणु रूप से 64 बिट int का मान सेट करने में सक्षम होना चाहिए।

मुझे इस पढ़ने में बहुत कुछ मुश्किल पाया गया, इसलिए सोचा कि मैं इसे सत्यापित करने के लिए परीक्षण करने का प्रयास करूंगा।

bool switcher = false; 

while(true) 
{ 
    if (switcher) 
     foo = a; 
    else 
     foo = b; 
    switcher = !switcher; 
} 

एक और धागा और जो foo का मूल्य की जाँच करेगा:: मैं a = 1844674407370955161; और b = 1144644202170355111; सेट

while (true) 
{ 
    __uint64_t blah = foo; 
    if ((blah != a) && (blah != b)) 
    { 
     cout << "Not atomic! " << blah << endl; 
    } 
} 

तो मैं एक साधारण जो दो मानों में से एक में एक चर सेट होगा एक धागे से कार्यक्रम में लिखा था । मैं इस कार्यक्रम को चलाता हूं और मुझे आउटपुट चेतावनी नहीं देता है कि blaha या b नहीं है।

बढ़िया है, लगता है कि यह शायद एक परमाणु लिखने है ... लेकिन फिर, मैं पहली बार धागा सीधे a और b स्थापित करने के लिए, की तरह इतना बदल दिया है: अचानक

bool switcher = false; 

while(true) 
{ 
    if (switcher) 
     foo = 1844674407370955161; 
    else 
     foo = 1144644202170355111; 
    switcher = !switcher; 
} 

मैं फिर से चलाने के लिए, और:

Not atomic! 1144644203261303193 
Not atomic! 1844674406280007079 
Not atomic! 1144644203261303193 
Not atomic! 1844674406280007079 

क्या बदल गया है? किसी भी तरह से मैं foo पर बड़ी संख्या में असाइन कर रहा हूं - क्या संकलक निरंतर संख्या को अलग-अलग संभालता है, या क्या मैंने सबकुछ गलत समझा है?

धन्यवाद!


1: Intel CPU documentation, section 8.1, Guaranteed Atomic Operations

2: GCC Development list discussing that GCC doesn't guarantee it in the documentation, but the kernel and other programs rely on it

+0

क्या संकलन करते समय आपको कोई चेतावनी मिली? – Nim

+0

मुझे नहीं लगता कि यह अपराधी है, लेकिन शाब्दिकों के पास डिफ़ॉल्ट रूप से int प्रकार है, इसलिए आप 1844674407370955161ULL और 1144644202170355111ULL को अक्षर के रूप में चाहते हैं। – etarion

+0

निम, संकलन करते समय कोई चेतावनी नहीं है, और -वॉल – Frederik

उत्तर

12

पाश वियोजन, मैं gcc साथ निम्नलिखित कोड प्राप्त:

.globl _switcher 
_switcher: 
LFB2: 
    pushq %rbp 
LCFI0: 
    movq %rsp, %rbp 
LCFI1: 
    movl $0, -4(%rbp) 
L2: 
    cmpl $0, -4(%rbp) 
    je L3 
    movq [email protected](%rip), %rax 
    movl $-1717986919, (%rax) 
    movl $429496729, 4(%rax) 
    jmp L5 
L3: 
    movq [email protected](%rip), %rax 
    movl $1486032295, (%rax) 
    movl $266508246, 4(%rax) 
L5: 
    cmpl $0, -4(%rbp) 
    sete %al 
    movzbl %al, %eax 
    movl %eax, -4(%rbp) 
    jmp L2 
LFE2: 

तो यह लगता है कि gcc 32-बिट तत्काल मूल्यों के साथ 32-बिट movl अनुदेश करने के लिए उपयोग करता है। एक निर्देश movq है जो 64-बिट रजिस्टर को स्मृति (या 64-बिट रजिस्टर में स्मृति) में स्थानांतरित कर सकता है, लेकिन ऐसा लगता है कि यह एक स्मृति पते पर तत्काल मान को स्थानांतरित करने में सक्षम नहीं है, इसलिए संकलक को मजबूर होना पड़ता है या तो एक अस्थायी रजिस्टर का उपयोग करने के लिए और फिर मान को स्मृति में ले जाएं, या movl पर उपयोग करें। आप इसे एक अस्थायी चर का उपयोग करके एक रजिस्टर का उपयोग करने के लिए मजबूर करने का प्रयास कर सकते हैं, लेकिन यह काम नहीं कर सकता है।

संदर्भ:

+0

दिलचस्प! उस समय को विसर्जित करने के लिए समय निकालने के लिए धन्यवाद! – Frederik

+0

आप किस कंपाइलर संस्करण, प्लेटफ़ॉर्म और कंपाइलर विकल्प का उपयोग कर रहे हैं? यह एक बहुत बड़ा अंतर बनाता है। 64 बिट लिखने पर केवल परमाणु होगा यदि ऑब्जेक्ट 8 बाइट गठबंधन है और 32 बिट मोड में चलने पर सिस्टम 64 बिट कोड चला रहा है (ओएस 32 बिट है, या ओएस 64 है, लेकिन बाइनरी 32 है) लिखने परमाणु –

+1

नहीं होगा जीसीसी 4.2, मैकोज़ एक्स, सीपीयू कोर i7, ओएस 64-बिट है, कोड x86_64 आर्किटेक्चर के लिए संकलित किया गया है। 64-बिट मान का लेखन परमाणु है, लेकिन 64-बिट तत्काल मानों को ओपोड में @AProgrammer के रूप में प्रदर्शित नहीं किया जा सकता है। तो संकलक को या तो इसे स्मृति में ले जाने से पहले तत्काल मूल्य को प्रतिलिपि बनाने के लिए प्रतिलिपि बनाना चाहिए, या इसे तत्काल मूल्य के दो 32-बिट आधा को कॉपी करने वाले मूल्य को गैर-सामूहिक रूप से संग्रहीत करना होगा। लिंक के लिए –

3

इंटेल सीपीयू प्रलेखन सही, गठबंधन 8 बाइट्स पढ़ा जाता है/राईट हमेशा परमाणु हाल हार्डवेयर पर (यहां तक ​​कि 32 बिट ऑपरेटिंग सिस्टम पर) कर रहे हैं।

आप हमें क्या नहीं बताते हैं, क्या आप 32 बिट सिस्टम पर 64 बिट हार्डवेयर का उपयोग कर रहे हैं? यदि ऐसा है, तो 8 बाइट लिखने की संभावना दो 4 बाइट में विभाजित की जाएगी संकलक द्वारा।

बस ऑब्जेक्ट कोड में प्रासंगिक अनुभाग पर एक नज़र डालें।

+0

हाय drhirsch, प्रणाली 64 बिट लिनक्स है। अनम आउट आउटपुट है: लिनक्स एकोर्न 2.6.35-25-सर्वर # 44 एसएमपी शुक्र फ़रवरी 11 15:50:10 जीएमटी 2011 x86_64 जीएनयू/लिनक्स – Frederik

12

http://www.x86-64.org/documentation/assembly.html

निर्देश के अंदर तत्काल मान 32 बिट रहते हैं।

कंपाइलर को 64 बिट्स परमाणु रूप से असाइनमेंट करने के लिए कोई रास्ता नहीं है, पहले पंजीकरण को भरकर और फिर उस रजिस्टर को चर पर ले जाया जा सकता है। यह संभवतः परिवर्तनीय को असाइन करने से अधिक महंगा है और क्योंकि भाषा द्वारा परमाणुता की आवश्यकता नहीं है, परमाणु समाधान का चयन नहीं किया जाता है।

+1

+1, वहां महान दस्तावेज़। धन्यवाद। –

+0

एक और महान जवाब! धन्यवाद! – Frederik

+0

यदि 8 बाइट मान और 8 बाइट पते दोनों के साथ तत्काल निर्देश चल रहे थे, तो परिणामस्वरूप निर्देश का आकार केवल भयानक होगा। देख सकते हैं कि वे इसके लिए एक डिकोडर क्यों नहीं बनाना चाहते थे! –

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