2011-08-04 13 views
13

मैं जीसीसी इनलाइन विधानसभा का उपयोग कर के लिए नया हूँ, और अगर सोच रहा था, एक x86 मल्टी कोर मशीन, एक spinlock (दौड़ की स्थिति के बिना) के रूप में (एटी & टी सिंटैक्स का उपयोग) लागू किया जा सकता:86 spinlock cmpxchg

 
spin_lock: 
mov 0 eax 
lock cmpxchg 1 [lock_addr] 
jnz spin_lock 
ret 

spin_unlock: 
lock mov 0 [lock_addr] 
ret 

उत्तर

21

आप सही पता नहीं है, लेकिन अपने एएसएम टूट गया है:

cmpxchg एक तत्काल संकार्य के साथ काम नहीं कर सकते, केवल पंजीकृत करता है।

lockmov के लिए मान्य उपसर्ग नहीं है। mov एक गठबंधन पते पर x86 पर परमाणु है, इसलिए आपको lock की आवश्यकता नहीं है।

यह कुछ समय हो गया है के बाद से मैं एटी & टी वाक्य रचना का उपयोग किया है मैं सब कुछ याद उम्मीद:

spin_lock: 
xorl %ecx, %ecx 
incl %ecx 
spin_lock_retry: 
xorl %eax, %eax 
lock; cmpxchgl %ecx, (lock_addr) 
jnz spin_lock_retry 
ret 

spin_unlock: 
movl $0 (lock_addr) 
ret 

ध्यान दें कि जीसीसी परमाणु builtins है, तो आप वास्तव में करने के लिए इनलाइन एएसएम का उपयोग करने की जरूरत नहीं है यह पूरा:

void spin_lock(int *p) 
{ 
    while(!__sync_bool_compare_and_swap(p, 0, 1)); 
} 

void spin_unlock(int volatile *p) 
{ 
    asm volatile (""); // acts as a memory barrier. 
    *p = 0; 
} 

बो नीचे कहते हैं, बंद कर दिया निर्देश उठाना लागत: हर एक आप का उपयोग अपने कैश फ्लश करने और अपने सिस्टम की स्मृति बस, जो काफी महंगा हो सकता है अगर आप पर्याप्त सीपीयू मिल गया है लॉक कर देना चाहिए। यहां तक ​​कि कई CPUs के बिना, यह अभी भी आसान है और लायक है उसके चारों ओर का अनुकूलन करने के:

void spin_lock(int volatile *p) 
{ 
    while(!__sync_bool_compare_and_swap(p, 0, 1)) 
    { 
     while(*p) _mm_pause(); 
    } 
} 

pause अनुदेश हाइपरथ्रेडिंग CPUs पर प्रदर्शन के लिए महत्वपूर्ण है जब आप कोड है कि इस तरह घूमती है मिल गया है - यह दूसरा धागा पर अमल की सुविधा देता है जबकि पहला धागा कताई है। सीपीयू पर जो pause का समर्थन नहीं करते हैं, इसे nop के रूप में माना जाता है।

+0

शून्य spin_lock के लिए पैरामीटर() भी अस्थिर घोषित किया जाना चाहिए? – ManRow

+1

नंबर '__sync_bool_compare_and_swap' पहले से ही इसे 'अस्थिर' के रूप में मानता है। –

+0

'spin_unlock' के अंदर मेमोरी बाधा के रूप में उपयोग किया जाने वाला एएसएम शायद मेमोरी क्लॉबर शामिल होना चाहिए। यद्यपि दूसरी ओर, '__sync_lock_release' है जो कि" लिखना बाधा, और 0 लिखने "के लिए डिज़ाइन किया गया है, बिना किसी एएसएम के बारे में सोचने की आवश्यकता के, और यह" कुछ हद तक पोर्टेबल "भी है। यह स्पष्ट रूप से पढ़ने की बाधा के रूप में काम नहीं करता है (यह _incidentially_ लक्ष्य आर्किटेक्चर पर करता है), लेकिन यह ठीक है। होने वाली सबसे बुरी चीज एक दुर्लभ, असंभव मामले में एक और थ्रेड एक अतिरिक्त स्पिन कर रही है। – Damon

3

यह स्मृति बस में कम विवाद डाल देंगे:

void spin_lock(int *p) 
{ 
    while(!__sync_bool_compare_and_swap(p, 0, 1)) while(*p); 
} 
+0

सहमत है, हालांकि यह कोड इतना अच्छा नहीं है। एक साधारण जबकि (* पी) आसानी से संकलक द्वारा अनुकूलित किया जा सकता है। कुछ बाधाएं जोड़ें। साथ ही, इंटेल चिप्स के लिए _mm_pause() जोड़ने से प्रदर्शन में काफी सुधार हो सकता है। –

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