2012-09-03 14 views
13

इस प्रश्न को एक साक्षात्कार में पूछा गया था। पहले भाग सिंगलटन वर्ग लिखा था:मल्टीथ्रेड के साथ सिंगलटन

class Singleton 
{ 
    static Singleton *singletonInstance; 
    Singleton() {} 

    public: 
    static Singleton* getSingletonInstance() 
    { 
     if(singletonInstance == null) 
     { 
      singletonInstance = new Singleton(); 
     } 
     return singletonInstance; 
    } 
}; 

तो मैं कैसे इस getSingletonInstance() एक बहु स्थिति में संभाल करने के लिए कहा गया था। मैं वास्तव में यकीन नहीं था, लेकिन मैं संशोधित रूप में:

class Singleton 
{ 
    static Singleton *singletonInstance; 
    Singleton() {} 
    static mutex m_; 

    public: 
    static Singleton* getSingletonInstance() 
    { 
     m_pend(); 
     if(singletonInstance == null) 
     { 
      singletonInstance = new Singleton(); 
     } 
     return singletonInstance; 
    } 

    static void releaseSingleton() 
    { 
     m_post(); 
    } 
}; 

तो मुझे बताया गया था कि हालांकि एक म्युटेक्स की आवश्यकता है, लंबित है और एक म्युटेक्स पोस्टिंग कुशल नहीं के रूप में यह समय लगता है। और इस स्थिति को संभालने का एक बेहतर तरीका है।

क्या कोई भी बहुसंख्यक परिस्थिति में सिंगलटन कक्षा को संभालने का एक बेहतर प्रभावी तरीका जानता है?

+12

सिंगलटन का उपयोग न करें? –

+6

मल्टीथ्रेड कोड में वैश्विक स्थिति का उपयोग अनंत सिरदर्द पाने का एक अच्छा तरीका है। संदेह तो stupidgleton के मामले में। –

+0

@CatPlusPlus: यह सरल है। अनाड़ी। –

उत्तर

20

सी में ++ 11, निम्नलिखित धागे की सुरक्षित initialisation प्रदर्शन करने के लिए गारंटी है: सी ++ 03 में

static Singleton* getSingletonInstance() 
{ 
    static Singleton instance; 
    return &instance; 
} 

, एक आम दृष्टिकोण ताला लगा होने की दोबारा जांच उपयोग करने के लिए किया गया था; यह देखने के लिए कि क्या ऑब्जेक्ट अनियंत्रित हो सकता है, और केवल म्यूटेक्स को लॉक कर रहा है या नहीं, यह एक ध्वज (या पॉइंटर स्वयं) की जांच कर रहा है। इसके लिए पॉइंटर (या एक संबंधित बूलियन ध्वज) परमाणु रूप से पढ़ने के कुछ प्रकार के गैर-मानक तरीके की आवश्यकता होती है; कई कार्यान्वयन गलत तरीके से एक सादे सूचक या bool का उपयोग करते हैं, इस बात की कोई गारंटी नहीं है कि एक प्रोसेसर पर परिवर्तन दूसरों पर दिखाई दे रहा है। कोड कुछ इस तरह लग सकता है, हालांकि मैं लगभग निश्चित रूप से कुछ गलत मिल गया है:

static Singleton* getSingletonInstance() 
{ 
    if (!atomic_read(singletonInstance)) { 
     mutex_lock lock(mutex); 
     if (!atomic_read(singletonInstance)) { 
      atomic_write(singletonInstance, new Singleton); 
     } 
    } 
    return singletonInstance; 
} 

यह काफी सही पाने के लिए मुश्किल है, इसलिए मेरा सुझाव है कि आप परेशान नहीं है। सी ++ 11 में, आप मानक परमाणु और म्यूटेक्स प्रकारों का उपयोग कर सकते हैं, अगर किसी कारण से आप उदाहरण के गतिशील आवंटन को रखना चाहते हैं।

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

2

यदि आपके पास सी ++ 11 आप singletonInstance एक परमाणु चर कर सकते हैं, तो एक की दोबारा जांच कर लॉक का उपयोग:

if (singletonInstance == NULL) { 
    lock the mutex 
    if (singletonInstance == NULL) { 
     singletonInstance = new Singleton; 
    } 
    unlock the mutex 
} 
return singletonInstance; 
+9

यदि आपका कंपाइलर सही ढंग से C++ 11 लागू करता है, तो आपको इसे लॉक करने की आवश्यकता नहीं है। 'स्थिर फू और getSingleton() {स्थिर फू foo {}; वापसी foo; } समवर्ती निष्पादन के तहत * * काम * होगा। – Xeo

+0

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

+0

ठीक है, मैंने पहले ही एक लिखा है, लेकिन सवाल वास्तव में एक डुप्लिकेट नहीं है, कम से कम मेरी राय में: http://stackoverflow.com/a/11711991/500104। – Xeo

2

आप वास्तव में सिंगलटन ताला चाहिए, और नहीं उदाहरण। उदाहरण के लॉकिंग की आवश्यकता है, कॉल करने वाले को संभाला जाना चाहिए

अद्यतन नमूना कोड (या शायद उदाहरण अपने आप में, के आधार पर एक अंतरफलक यह उजागर करता है कि किस तरह की):

#include <mutex> 

class Singleton 
{ 
    static Singleton *singletonInstance; 
    Singleton() {} 
    static std::mutex m_; 

    public: 

    static Singleton* getSingletonInstance() 
    { 
     std::lock_guard<std::mutex> lock(m_); 
     if(singletonInstance == nullptr) 
     { 
      singletonInstance = new Singleton(); 
     } 
     return singletonInstance; 
    } 
} 
2

यदि आप POSIX धागे का उपयोग करते हैं तो आप pthread_once_t और pthread_key_t सामान का उपयोग कर सकते हैं, इस तरह आप पूरी तरह से mutexes का उपयोग करने से बच सकते हैं।

template<class T> class ThreadSingleton : private NonCopyable { 
public: 
    ThreadSingleton(); 
    ~ThreadSingleton(); 

    static T& instance(); 

private: 
    ThreadSingleton(const ThreadSingleton&); 
    const ThreadSingleton& operator=(const ThreadSingleton&) 

    static pthread_once_t once_; 
    static pthread_key_t key_; 

    static void init(void); 
    static void cleanUp(void*); 
}; 

और कार्यान्वयन: उदाहरण के लिए:

template<class T> pthread_once_t ThreadSingleton<T>::once_ = PTHREAD_ONCE_INIT; 
template<class T> pthread_key_t ThreadSingleton<T>::key_; 

template<class T> 
T& ThreadSingleton<T>::instance() 
{ 
    pthread_once(&once_,init); 

    T* value = (T*)pthread_getspecific(key_); 
    if(!value) 
    { 

     value = new T(); 
     pthread_setspecific(key_,value); 
    } 
    return *value; 
} 

template<class T> void ThreadSingleton<T>::cleanUp(void* data) 
{ 
    delete (T*)data; 
    pthread_setspecific(key_,0); 
} 

template<class T> void ThreadSingleton<T>::init() 
{ 
    pthread_key_create(&key_,cleanUp); 
} 
+0

मुझे लगता है कि सवाल एक एकल उदाहरण बनाने के बारे में है, प्रति थ्रेड नहीं। –

+0

ऐसा नहीं है कि मैं इस सवाल को कैसे समझता हूं .. मैंने इसे फिर से पढ़ा और मुझे लगता है कि आप सही हैं। माफ़ कीजिये। – piokuc

12

रूप @piokuc सुझाव दिया, आप भी उपयोग कर सकते हैं एक बार यहाँ कार्य करते हैं।

#include <mutex> 

static void init_singleton() { 
    singletonInstance = new Singleton; 
} 
static std::once_flag singleton_flag; 

Singleton* getSingletonInstance() { 
    std::call_once(singleton_flag, init_singleton); 
    return singletonInstance; 
} 

और, हाँ, यह समझदारी से काम करेंगे, तो new Singleton एक अपवाद फेंकता है: आप सी ++ 11 है।

+1

धन्यवाद। मुझे एक बार समारोह के बारे में पता नहीं था। – madu