2013-02-24 117 views
25

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

+0

क्या यह उत्तर सभी प्लेटफॉर्म और प्रोग्रामिंग भाषाओं के लिए होना चाहिए जो pthreads या कुछ सबसेट का समर्थन करते हैं? मैं pthreads, ऑपरेटिंग सिस्टम और प्रोग्रामिंग भाषाओं के बीच संबंधों को पूरी तरह से समझ नहीं पा रहा हूं लेकिन ऐसा लगता है कि ये रिश्ते प्रासंगिक हो सकते हैं। –

उत्तर

7

जावा में परमाणु चर कक्षाएं प्रोसेसर द्वारा प्रदान की गई तुलना और स्वैप निर्देशों का लाभ लेने में सक्षम हैं। , http://www.ibm.com/developerworks/library/j-jtp11234/

13

परमाणु संचालन लाभ उठाने प्रोसेसर का समर्थन (तुलना और स्वैप निर्देश) और सब पर ताले का उपयोग नहीं करते जबकि ताले अधिक ओएस आधारित होता है तथा पर अलग ढंग से प्रदर्शन, के लिए:

यहाँ भिन्नताओं की एक विस्तृत विवरण दिया गया है उदाहरण, विन और लिनक्स।

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

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

16

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

तकनीकी रूप से, परमाणु अधिकांश प्लेटफ़ॉर्म पर मेमोरी बस को लॉक कर देगा। हालांकि, दो शानदार विवरण हैं:

  • मेमोरी बस लॉक के दौरान थ्रेड को निलंबित करना असंभव है, लेकिन एक म्यूटेक्स लॉक के दौरान थ्रेड को निलंबित करना संभव है। यही कारण है कि आपको लॉक-फ्री गारंटी मिलती है (जो लॉकिंग के बारे में कुछ भी नहीं कहती है - यह गारंटी देता है कि कम से कम एक धागा प्रगति करता है)।
  • म्यूटेक्स अंततः परमाणुओं के साथ कार्यान्वित किया जा रहा है। चूंकि आपको म्यूटेक्स को लॉक करने के लिए कम से कम एक परमाणु ऑपरेशन की आवश्यकता होती है, और एक म्यूटेक्स को अनलॉक करने के लिए एक परमाणु ऑपरेशन की आवश्यकता होती है, इसलिए म्यूटेक्स लॉक करने में कम से कम दो बार लगते हैं, यहां तक ​​कि सबसे अच्छे मामलों में भी।
+0

यह समझना महत्वपूर्ण है कि यह संकलक के लिए सर्वोत्तम मशीन निर्देश (इस मामले में लॉक-फ्री निर्देश) उत्पन्न करने के लिए प्लेटफ़ॉर्म का समर्थन करता है। मुझे लगता है कि @Cort Ammon "समर्थित" द्वारा इसका मतलब है। इसके अलावा कुछ म्यूटेक्स कुछ या सभी धागे के लिए आगे की प्रगति या निष्पक्षता के बारे में गारंटी दे सकते हैं जो सरल परमाणु निर्देशों द्वारा नहीं किए जाते हैं। –

1

परमाणु पूर्णांक एक उपयोगकर्ता मोड वहाँ आपत्ति यह एक म्युटेक्स जो कर्नेल मोड में चलता है की तुलना में अधिक कुशल है के लिए है। परमाणु पूर्णांक का दायरा एक ही अनुप्रयोग है जबकि म्यूटेक्स का दायरा मशीन पर चल रहे सभी सॉफ़्टवेयर के लिए है।

+0

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

1

Mutex एक कर्नेल स्तर अर्थपूर्ण है जो Process level पर पारस्परिक बहिष्करण प्रदान करता है। ध्यान दें कि प्रक्रिया प्रक्रियाओं में आपसी बहिष्कार को विस्तारित करने में मदद मिल सकती है न कि केवल एक प्रक्रिया (थ्रेड के लिए) के भीतर। यह महंगा है।

परमाणु काउंटर, AtomicInteger उदाहरण के लिए, सीएएस पर आधारित है, और आम तौर पर सफल होने तक ऑपरेशन करने का प्रयास करने का प्रयास करते हैं। असल में, इस मामले में, थ्रेड दौड़ते हैं या बढ़ते मूल्य को कम करने के लिए प्रतिस्पर्धा करते हैं। यहां, आप वर्तमान मूल्य पर काम करने की कोशिश कर रहे थ्रेड द्वारा अच्छे CPU चक्रों का उपयोग कर सकते हैं।

चूंकि आप काउंटर को बनाए रखना चाहते हैं, इसलिए आपके उपयोग के मामले में AtomicInteger \ AtomicLong सबसे अच्छा होगा।

1

अधिकांश प्रोसेसर ने परमाणु पढ़ने या लिखने का समर्थन किया है, और अक्सर एक परमाणु cmp & स्वैप। इसका मतलब यह है कि प्रोसेसर स्वयं एक ही ऑपरेशन में नवीनतम मूल्य लिखता है या पढ़ता है, और सामान्य पूर्णांक पहुंच की तुलना में कुछ चक्र खो सकते हैं, खासकर जब संकलक परमाणु संचालन के आसपास लगभग सामान्य के अनुकूल नहीं हो सकता है।

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

यदि आप वृद्धि करने की कोशिश कर रहे हैं, तो आपका आधुनिक प्रोसेसर शायद परमाणु वृद्धि/कमी का समर्थन करता है, जो बहुत अच्छा होगा।

यदि ऐसा नहीं होता है, तो इसे या तो प्रोसेसर परमाणु cmp & स्वैप, या एक म्यूटेक्स का उपयोग करके कार्यान्वित किया जाता है।

Mutex:

get the lock 
read 
increment 
write 
release the lock 

परमाणु सीएमपी & स्वैप:

atomic read the value 
calc the increment 
do{ 
    atomic cmpswap value, increment 
    recalc the increment 
}while the cmp&swap did not see the expected value 

तो यह दूसरा संस्करण, एक पाश [बैठाना एक और प्रोसेसर हमारे परमाणु संचालन के बीच मूल्य इतना मूल्य नहीं रह गया है से मेल खाता है वृद्धि कर देता है, और वृद्धि गलत होगी] जो लंबे समय तक हो सकती है [यदि कई प्रतियोगियों हैं], लेकिन आम तौर पर म्यूटेक्स संस्करण से तेज होना चाहिए, लेकिन म्यूटेक्स संस्करण उस प्रोसेसर को कार्य स्विच करने की अनुमति दे सकता है।

3

एक न्यूनतम (मानकों के अनुरूप) म्युटेक्स कार्यान्वयन 2 मूल सामग्री की आवश्यकता है:

  • एक तरह से atomically धागे के बीच एक राज्य परिवर्तन संप्रेषित करने के लिए ('बंद कर दिया' राज्य)
  • स्मृति बाधाओं स्मृति आपरेशन लागू करने के लिए संरक्षित संरक्षित क्षेत्र के अंदर रहने के लिए म्यूटेक्स द्वारा।

सी ++ मानक के संबंध में 'सिंक्रनाइज़-इन' संबंधों के कारण आप इसे किसी भी तरह से सरल बना सकते हैं।

एक न्यूनतम (सही) क्रियान्वयन ऐसा दिखाई दे सकता है: (यह निष्पादन की धागा निलंबित नहीं कर सकता) अपनी सादगी के कारण

class mutex { 
    std::atomic<bool> flag{false}; 

public: 
    void lock() 
    { 
     while (flag.exchange(true, std::memory_order_relaxed)); 
     std::atomic_thread_fence(std::memory_order_acquire); 
    } 

    void unlock() 
    { 
     std::atomic_thread_fence(std::memory_order_release); 
     flag.store(false, std::memory_order_relaxed); 
    } 
}; 

, यह संभावना कम विवाद के तहत, इस कार्यान्वयन से बेहतर साबित है कि, एक std::mutex है । लेकिन फिर भी, यह देखने के लिए कि प्रत्येक पूर्णांक वेतन वृद्धि, इस म्युटेक्स द्वारा संरक्षित, निम्न कार्रवाई की आवश्यकता है आसान है:

  • एक atomic दुकान म्युटेक्स
  • एक atomic तुलना और स्वैप जारी करने के लिए (पढ़ने -modify-लिखने) म्युटेक्स (संभवतः कई बार)
  • एक पूर्णांक वेतन वृद्धि

आप तुलना कि एक स्टैंडअलोन std::atomic<int> है कि एक ही (बिना शर्त के साथ वृद्धि की जाती है) के साथ पढ़ा प्राप्त करने के लिए -मोडाइफी-लिखो (उदाहरण के लिए। fetch_add), यह अपेक्षा करना उचित है कि एक परमाणु संचालन (उसी क्रम मॉडल का उपयोग करके) उस मामले को बेहतर प्रदर्शन करेगा जिससे म्यूटेक्स का उपयोग किया जाता है।

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

  • कोई संबंधित समस्या नहीं^_^