2012-11-09 16 views
6

की थ्रेड सुरक्षा मैं थ्रेड सुरक्षा की अवधारणा को समझता हूं। एक एकल चर की रक्षा करने की कोशिश करते समय मैं थ्रेड सुरक्षा को सरल बनाने के लिए सलाह की तलाश में हूं।एक परिवर्तनीय

मैं एक चर राशि कहते हैं:

double aPass; 

और मैं इस चर की रक्षा करना चाहते हैं, तो मैं एक म्युटेक्स बनाएँ:

pthread_mutex_t aPass_lock; 

अब दो अच्छा तरीके मैं ऐसा करने के बारे में सोच सकते हैं लेकिन वे दोनों को परेशान नुकसान है। पहले चर धारण करने के लिए एक धागा सुरक्षित वर्ग बनाने के लिए है:

class aPass { 
    public: 
     aPass() { 
      pthread_mutex_init(&aPass_lock, NULL); 
      aPass_ = 0; 
     } 

     void get(double & setMe) { 
      pthread_mutex_lock(aPass_lock); 
      setMe = aPass_ 
      pthread_mutex_unlock(aPass_lock); 
     } 

     void set(const double setThis) { 
      pthread_mutex_lock(aPass_lock); 
      aPass_ = setThis; 
      pthread_mutex_unlock(aPass_lock); 
     } 
    private: 
     double aPass_; 
     pthread_mutex_t aPass_lock; 
}; 

अब इस उसे स्पर्श करें, याय रखेंगे aPass पूरी तरह से सुरक्षित है, कुछ भी गलत हो सकता है और कभी! हालांकि उस गड़बड़ी को देखो और इसे एक्सेस करते समय भ्रम की कल्पना करें। कुल।

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

pthread_mutex_lock(aPass_lock); 
    do something with aPass 
pthread_mutex_unlock(aPass_lock); 

लेकिन क्या कोई नई परियोजना, क्या हुआ अगर आप एक समय यह लॉक करने के लिए भूल जाते हैं पर आता है। मुझे डीबगिंग थ्रेड समस्याओं को पसंद नहीं है जो वे कठिन हैं।

क्या कोई अच्छा तरीका है (pthreads का उपयोग करना क्योंकि मुझे क्यूएनएक्स का उपयोग करना है जिसमें थोड़ा बढ़ावा समर्थन है) एक बड़े वर्ग की आवश्यकता के बिना एकल चर को लॉक करने के लिए और यह सुरक्षित है तो बस इसके साथ जाने के लिए एक म्यूटेक्स लॉक बनाना?

+0

यह चर वैश्विक चर है? मुझे नहीं लगता कि आपके पास बहुत अधिक विकल्प है .. जब तक कि आप एक सामान्य थ्रेड सुरक्षित कंटेनर क्लास बनाना नहीं चाहते हैं - यह आपको कुछ कोड बचाएगा यदि आपको इसे दूसरे var में करना है। –

+0

क्या आप एक टेम्पलेट वर्ग की तरह मतलब है? यह बहुत अच्छा लगता है। –

+0

भी, क्या आपके डिजाइन द्वारा var को डुप्लिकेट करना संभव नहीं है? एपस एक वर्ग है इसलिए मुझे कई ऑब्जेक्ट्स मिल सकती हैं क्योंकि मुझे –

उत्तर

3

मेरे समाधान पर विस्तार करने के लिए, यह ऐसा कुछ होगा।

template <typename ThreadSafeDataType> 
class ThreadSafeData{ 
    //.... 
private: 
    ThreadSafeDataType data; 
    mutex mut; 
}; 

class apass:public ThreadSafeData<int> 

इसके अतिरिक्त, इसे अद्वितीय बनाने के लिए, सभी ऑपरेटरों और सदस्यों को स्थैतिक बनाना सर्वोत्तम हो सकता है। यह आप का उपयोग करने के CRTP यानी

template <typename ThreadSafeDataType,class DerivedDataClass> 
class ThreadSafeData{ 
//.... 
}; 
class apass:public ThreadSafeData<int,apass> 
+1

SO में आपका स्वागत है! कृपया अपने संचार में txt-speak का उपयोग न करें, इसके लिए यहां कोई आवश्यकता नहीं है और यह आम तौर पर फहरा हुआ है। – GManNickG

1

आप एक वर्ग बना सकते हैं जो आपके चर के चारों ओर एक सामान्य रैपर के रूप में कार्य करता है जिससे इसे एक्सेस सिंक्रनाइज़ किया जा सके।

असाइनमेंट के लिए ऑपरेटर ओवरलोडिंग जोड़ें और आप कर चुके हैं।

+0

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

+0

आप एक टेम्पलेट क्लास बना सकते हैं जो किसी भी डेटा प्रकार के साथ काम करेगा। – thedayofcondor

+0

@ कार्तिक टी कोड देखें ... मेरा सी ++ थोड़ा जंगली है और आईडीई के बिना मेरे सिर के ऊपर लिखने में सक्षम नहीं होगा ... मुझे बहुत पुराना हो रहा है – thedayofcondor

1

, पर विचार करें RAII idiom का उपयोग नीचे कोड सिर्फ विचार है की जरूरत है काम करने के लिए के लिए यह परीक्षण नहीं किया है:

template<typename T, typename U> 
struct APassHelper : boost::noncoypable 
{ 
    APassHelper(T&v) : v_(v) { 
    pthread_mutex_lock(mutex_); 
    } 
    ~APassHelper() { 
    pthread_mutex_unlock(mutex_); 
    } 
    UpdateAPass(T t){ 
    v_ = t; 
    } 
private: 
    T& v_; 
    U& mutex_; 
}; 

double aPass; 
int baPass_lock; 
APassHelper<aPass,aPass_lock) temp; 
temp.UpdateAPass(10); 
+0

यह अभी भी उपयोगकर्ताओं को मैन्युअल रूप से सहायक का उपयोग करने की आवश्यकता है, जिसे ओपी –

2

आप आसानी से अपने ही वर्ग बना सकते हैं कि ताले निर्माण पर mutex, और विनाश पर इसे खोल देता है। इस तरह, कोई फर्क नहीं पड़ता कि म्यूटेक्स क्या होता है बदले में वापस किया जाएगा, भले ही एक अपवाद फेंक दिया गया हो, या कोई रास्ता लिया जाता है।

class MutexGuard 
{ 
    MutexType & m_Mutex; 
public: 

    inline MutexGuard(MutexType & mutex) 
     : m_Mutex(mutex) 
    { 
     m_Mutex.lock(); 
    }; 

    inline ~MutexGuard() 
    { 
     m_Mutex.unlock(); 
    }; 
} 


class TestClass 
{ 
    MutexType m_Mutex; 
    double m_SharedVar; 

    public: 
     TestClass() 
      : m_SharedVar(4.0) 
     { } 

     static void Function1() 
     { 
      MutexGuard scopedLock(m_Mutex); //lock the mutex 
      m_SharedVar+= 2345; 
      //mutex automatically unlocked 
     } 
     static void Function2() 
     { 
      MutexGuard scopedLock(m_Mutex); //lock the mutex 
      m_SharedVar*= 234; 
      throw std::runtime_error("Mutex automatically unlocked"); 
     } 

} 

चर m_SharedVar Function1() और Function2() के बीच पारस्परिक अपवर्जन सुनिश्चित किया जाता है, और हमेशा वापसी पर अनलॉक कर दिया जाएगा।

बूस्ट ने इसे पूरा करने के लिए प्रकारों में निर्माण किया है: boost :: scoped_locked, boost :: lock_guard।

+1

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

+3

उसने आपको दिखाया है कि कैसे अपना खुद का स्कॉप्ड लॉक –

1

आपको मिल/सेट के बजाय ऑपरेटरों का उपयोग करके अपने aPass वर्ग को संशोधित कर सकते हैं:

class aPass { 
public: 
    aPass() { 
     pthread_mutex_init(&aPass_lock, NULL); 
     aPass_ = 0; 
    } 

    operator double() const { 
     double setMe; 
     pthread_mutex_lock(aPass_lock); 
     setMe = aPass_; 
     pthread_mutex_unlock(aPass_lock); 
     return setMe; 
    } 

    aPass& operator = (double setThis) { 
     pthread_mutex_lock(aPass_lock); 
     aPass_ = setThis; 
     pthread_mutex_unlock(aPass_lock); 
     return *this; 
    } 
private: 
    double aPass_; 
    pthread_mutex_t aPass_lock; 
}; 

उपयोग:

aPass a; 
a = 0.5; 
double b = a; 

इस कोर्स के अन्य प्रकार का समर्थन करने के टेम्प्लेट की जा सकती है। ध्यान दें कि इस मामले में एक म्यूटेक्स अधिक है। आम तौर पर, छोटे डेटा-प्रकारों के लोड और स्टोर की सुरक्षा करते समय स्मृति बाधाएं पर्याप्त होती हैं। यदि संभव हो तो आपको सी ++ 11 std::atomic<double> का उपयोग करना चाहिए।

5
std::atomic<double> aPass; 

बशर्ते आपके पास सी ++ 11 है।

+0

दुर्भाग्य से नहीं, मेरे पास C++ 11 नहीं है –