दुर्भाग्यवश, मैट के उत्तर में डबल-चेक लॉकिंग कहा जाता है जो सी / सी ++ मेमोरी मॉडल द्वारा समर्थित नहीं है। (यह जावा 1.5 और बाद में समर्थित है? और मुझे लगता है .NET? मेमोरी मॉडल।) इसका मतलब है कि उस समय के बीच जब pObj == NULL
चेक होता है और जब लॉक (mutex) अधिग्रहित किया गया है, pObj
पहले से ही किसी अन्य थ्रेड पर असाइन किया जा सकता है। थ्रेड स्विचिंग तब भी होती है जब भी ओएस चाहता है कि प्रोग्राम के "लाइन" के बीच न हो (जिसका अर्थ अधिकांश भाषाओं में पोस्ट-संकलन नहीं है)।
इसके अलावा, जैसा कि मैट स्वीकार करता है, वह ओएस आदिम के बजाए एक लॉक के रूप में int
का उपयोग करता है। ऐसा मत करो। उचित ताले को स्मृति बाधा निर्देशों, संभावित रूप से कैश-लाइन फ्लश, और इसी तरह के उपयोग की आवश्यकता होती है; लॉकिंग के लिए अपने ऑपरेटिंग सिस्टम के प्राइमेटिव का उपयोग करें। यह विशेष रूप से महत्वपूर्ण है क्योंकि उपयोग किए जाने वाले प्राइमेटिव अलग-अलग CPU लाइनों के बीच बदल सकते हैं जो आपका ऑपरेटिंग सिस्टम चल रहा है; सीपीयू फू पर क्या काम करता है CPU Foo2 पर काम नहीं कर सकता है। अधिकांश ऑपरेटिंग सिस्टम या तो मूल रूप से पॉज़िक्स धागे (pthreads) का समर्थन करते हैं या उन्हें ओएस थ्रेडिंग पैकेज के लिए एक रैपर के रूप में पेश करते हैं, इसलिए अक्सर उनका उपयोग करके उदाहरणों को चित्रित करना सबसे अच्छा होता है।
यदि आपका ऑपरेटिंग सिस्टम उपयुक्त प्राइमेटिव प्रदान करता है, और यदि आपको पूरी तरह से प्रदर्शन के लिए इसकी आवश्यकता है, तो इस प्रकार के लॉकिंग / प्रारंभिकरण के बजाय आप एक साझा वैश्विक चर प्रारंभ करने के लिए परमाणु तुलना और स्वैप ऑपरेशन का उपयोग कर सकते हैं। अनिवार्य रूप से, जो आप लिखते हैं वह इस तरह दिखेगा:
MySingleton *MySingleton::GetSingleton() {
if (pObj == NULL) {
// create a temporary instance of the singleton
MySingleton *temp = new MySingleton();
if (OSAtomicCompareAndSwapPtrBarrier(NULL, temp, &pObj) == false) {
// if the swap didn't take place, delete the temporary instance
delete temp;
}
}
return pObj;
}
यह केवल तभी काम करता है जब आपके सिंगलटन के कई उदाहरण (एक थ्रेड जो एक साथ GetSingleton() को आमंत्रित करने के लिए होता है), और फिर अतिरिक्त दूर फेंक दें। मैक ओएस एक्स पर OSAtomicCompareAndSwapPtrBarrier
फ़ंक्शन प्रदान किया गया है? अधिकांश ऑपरेटिंग सिस्टम एक समान आदिम प्रदान करते हैं? यह जांचता है कि pObj
NULL
है और केवल इसे वास्तव में temp
पर सेट करता है यदि यह है। यह वास्तव में हार्डवेयर समर्थन का उपयोग करता है, सचमुच केवल स्वैप एक बार निष्पादित करता है और बताता है कि यह हुआ है या नहीं।
यदि आपका ओएस इन दो चरम सीमाओं के बीच है, तो इसका लाभ उठाने की एक और सुविधा pthread_once
है। यह आपको एक फ़ंक्शन सेट करने देता है जो केवल एक बार चलाया जाता है - मूल रूप से सभी लॉकिंग / बाधा / आदि कर कर। आपके लिए चालबाजी - कोई फर्क नहीं पड़ता कि कितनी बार इसे बुलाया गया है या कितने धागे इसे बुलाया गया है।