2012-09-06 30 views
11

मैंने थ्रेड-सुरक्षित डबल चेक लॉकिंग (सिंगलेट्स या आलसी init के लिए) पर विचार करने के कई प्रश्न पढ़े हैं। कुछ धागे में, जवाब यह है कि पैटर्न पूरी तरह टूटा हुआ है, अन्य समाधान का सुझाव देते हैं।सी ++ 11: आलसी प्रारंभिक के लिए सुरक्षित डबल चेक लॉकिंग। मुमकिन?

तो मेरा सवाल है: क्या सी ++ में पूरी तरह से थ्रेड-सुरक्षित डबल चेक किए गए लॉकिंग पैटर्न को लिखने का कोई तरीका है? यदि हां, तो यह कैसा दिखता है।

हम सी ++ 11 मान सकते हैं, अगर इससे चीज़ें आसान हो जाती हैं। जहां तक ​​मुझे पता है, सी ++ 11 मेमोरी मॉडल में सुधार हुआ है जो आवश्यक सुधारों को उत्पन्न कर सकता है।

मुझे पता है कि डबल-चेक संरक्षित परिवर्तनीय अस्थिर बनाकर जावा में यह संभव है। चूंकि सी ++ 11 ने जावा के एक से मेमोरी मॉडल के बड़े हिस्से उधार लिया, इसलिए मुझे लगता है कि यह संभव हो सकता है, लेकिन कैसे?

+5

आप सी ++ 11 का उपयोग कर सकते हैं, बस की अनदेखी पूरे डबल व्यापार ताला लगा चेक किया था और या तो स्थिर स्थानीय चर या 'std :: call_once' का उपयोग करें। –

+0

स्थिर स्थानीय लोग आलसी शुरू कर रहे हैं? और 'call_once' के बारे में: यह कैसे सुनिश्चित करता है कि कॉल एक बार चर के पूर्ण रूप से निर्मित संदर्भ नहीं लिखेगा? – gexicide

+3

हां, स्थैतिक स्थानीय लोगों को थ्रेड-सुरक्षित तरीके से आलसी शुरू किया जाता है। और 'call_once' यह सुनिश्चित करता है कि विषय केवल एक बार ही कहा जाता है; और वास्तव में फ़ंक्शन रिटर्न निष्पादित करने वाले व्यक्ति के सामने 'call_once' रिटर्न' के लिए कोई अन्य कॉल नहीं है (आप यहां http://en.cppreference.com/w/cpp/thread/call_once पढ़ सकते हैं)। यह कार्यान्वयन पर निर्भर करता है। ये दो चीजें मूल रूप से मौजूद हैं इसलिए आप अधिक बग डबल-चेक लॉकिंग कार्यान्वयन के साथ परेशान नहीं करना चाहते हैं। –

उत्तर

16

, बस इतना की तरह, lazily initialized Singletons के लिए एक स्थिर स्थानीय चर का उपयोग:

MySingleton* GetInstance() { 
    static MySingleton instance; 
    return &instance; 
} 

(सी ++ 11) मानक पहले से ही गारंटी देता है कि स्थैतिक चर एक threadsafe ढंग से प्रारंभ कर रहे हैं और यह है कि संभावना लगती है इसे कम से कम मजबूत और निष्पादक के रूप में कार्यान्वित करें जो आप स्वयं लिखते हैं।

प्रारंभ की threadsafety (सी ++ 11) मानक के §6.7.4 में पाया जा सकता:

नियंत्रण जबकि चर प्रारंभ किया जा रहा है, समवर्ती निष्पादन करेगा समवर्ती घोषणा में प्रवेश करती है तो प्रारंभिक समापन के लिए प्रतीक्षा करें।

+11

यह पागल है। क्यों, ओह क्यों, क्या आप कभी एक सूचक वापस कर देंगे यदि यह ** ** ** शून्य नहीं हो सकता है? –

+1

@MatthieuM .: मुख्य रूप से क्योंकि यह अंतर्निहित वस्तु की प्रतिलिपि बनाने के इच्छुक लोगों को कम करता है। बेशक एक अच्छी तरह से डिज़ाइन किया गया सिंगलटन ** ** में एक प्रतिलिपि बनाने वाला नहीं होना चाहिए, लेकिन फिर भी। मैं वास्तव में नहीं देखता कि उस मामले में मूल्य मामलों द्वारा संदर्भ बनाम वापसी द्वारा वापसी कैसे की जाती है। इसलिए मैं मुश्किल से उस पागल को बुलाऊंगा। – Grizzly

+2

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

3

चूंकि आप एक वैध डीसीएलपी सी ++ 11 कार्यान्वयन देखना चाहते थे, तो यहां एक है।

व्यवहार पूरी तरह से थ्रेड-सुरक्षित है और ग्रिज़ली के जवाब में GetInstance() के समान है।

std::mutex mtx; 
std::atomic<MySingleton *> instance_p{nullptr}; 

MySingleton* GetInstance() 
{ 
    auto *p = instance_p.load(std::memory_order_acquire); 

    if (!p) 
    { 
     std::lock_guard<std::mutex> lck{mtx}; 

     p = instance_p.load(std::memory_order_relaxed); 
     if (!p) 
     { 
      p = new MySingleton; 
      instance_p.store(p, std::memory_order_release); 
     } 
    } 

    return p; 
} 
+0

प्रैक्टिस में, आप फंक्शन के बाहर स्टेटिक्स के बजाए फ़ंक्शन के बाहर ग्लोबल्स के रूप में अपने 'mtx' और' instance_p' चर घोषित करना चाहते हैं, अन्यथा आप संकलक के प्रारंभिक चेक के प्रारंभिक चेक के लिए कीमत चुका रहे हैं _every_ कॉल पर 'mtx' और 'instance_p', डबल-चेक किए गए लॉकिंग के बिंदु को हराकर (प्रदर्शन के अनुसार आप शायद सिंगलटन को स्थैतिक के रूप में घोषित कर सकते हैं)। – BeeOnRope

+0

@BeeOnRope मान्य बिंदु .. मैंने वह परिवर्तन किया है। – LWimsey

+0

आप यह जोड़ना चाहते हैं कि आप मूल रूप से कभी भी इस कोड को लिखना नहीं चाहते हैं। ग्रीज़ली का जवाब अधिक संक्षेप में है और संकलक भविष्य में और अधिक जादू डाल सकता है ताकि इसे इस कोड से तेज़ी से बनाया जा सके। – gexicide

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

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