5

मैं बहु-थ्रेडिंग के लिए सबसे सरल म्यूटेक्स दृष्टिकोण के बारे में पूछना चाहता हूं। क्या निम्न कोड थ्रेड-सुरक्षित (त्वरित-एन-गंदा) है?सरल म्यूटेक्स कभी। क्या यह उदाहरण काम करता है? क्या यह धागा सुरक्षित है?

class myclass 
{ 
    bool locked; 
    vector<double> vals; 

    myclass(); 
    void add(double val); 
}; 

void myclass::add(double val) 
{ 
    if(!locked) 
    { 
     this->locked = 1; 
     this->vals.push_back(val); 
     this->locked = 0; 
    } 
    else 
    { 
     this->add(val); 
    } 
} 

int main() 
{ 
    myclass cls; 
    //start parallelism 
    cls.add(static_cast<double>(rand())); 
} 

क्या यह काम करता है? क्या यह धागा सुरक्षित है? मैं बस यह समझने की कोशिश कर रहा हूं कि सबसे सरल म्यूटेक्स कैसे लिखा जा सकता है।

यदि आपके पास मेरे उदाहरण के बारे में कोई सलाह है, तो अच्छा होगा।

धन्यवाद।

यह कहने के लिए धन्यवाद कि यह काम नहीं करता है। क्या आप कृपया एक फिक्स का सुझाव दे सकते हैं जो संकलक स्वतंत्र है?

+5

सही म्यूटेक्स तंत्र बनाना एक जटिल व्यवसाय है। मैं पहले से ही कुछ इस्तेमाल करूँगा। – andre

+0

आम तौर पर, म्यूटेक्स जैसे सिंक्रनाइज़ेशन प्राइमेटिव्स को कुछ परमाणुता (अक्सर सीपीयू निर्देश स्तर पर) की आवश्यकता होती है। यहां एक दिलचस्प लिंक मिला है: http://lists.canonical.org/pipermail/kragen-tol/1999-August/000457.html – Tom

+0

सबसे सरल म्यूटेक्स (या सामान्य रूप से सिंक्रनाइज़ेशन निर्माण) वह है जिसे आपको आवश्यकता नहीं है; -) – delnan

उत्तर

8

क्या यह धागा-सुरक्षित है?

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

कम से कम, आपको लॉक को लागू करने के लिए परमाणु परीक्षण-और-सेट ऑपरेशन की आवश्यकता है इस तरह।

std::atomic_flag locked; 

if (!locked.test_and_set()) { 
    vals.push_back(val); 
    locked.clear(); 
} else { 
    // I don't know exactly what to do here; 
    // but recursively calling add() is a very bad idea. 
} 

या बेहतर अभी तक: सी ++ 11 लाइब्रेरी में ऐसी कोई बात प्रदान करता है

std::mutex mutex; 

std::lock_guard<std::mutex> lock(mutex); 
vals.push_back(val); 

यदि आप किसी पुराने कार्यान्वयन है, तो आप जो कुछ भी एक्सटेंशन पर भरोसा करना होगा/पुस्तकालयों में उपलब्ध हैं आपके लिए, क्योंकि भाषा या मानक पुस्तकालय में तब कुछ भी उपयोगी नहीं था।

+0

हम्मम्म। उत्तर के लिए धन्यवाद। मैं वीएस -2010 और जी ++ का उपयोग कर रहा हूं, जहां पहला म्यूटक्स का समर्थन नहीं करता है। कोई अन्य कंपाइलर स्वतंत्र विचार? –

+1

@ सैमरएफैच: [बूस्ट। थ्रेड] (http://www.boost.org/doc/libs/release/doc/html/thread.html) और [बस :: थ्रेड] (http: //www.stdthread .co.uk /) पुस्तकालयों में सी ++ 11 म्यूटेक्स के लिए पोर्टेबल और (अधिक या कम) प्रत्यक्ष प्रतिस्थापन है। ऐसा लगता है कि विंडोज एपीआई (महत्वपूर्ण खंड, या जिसे वे कहते हैं); जाहिर है कि यह कंपाइलर-स्वतंत्र नहीं है, इसलिए आपको उपयोग करने के लिए चुनने के लिए कुछ सावधानीपूर्वक '# परिभाषित' की आवश्यकता होगी। –

+0

@MikeSymour अगर मैं बूस्ट म्यूटेक्स का उपयोग उदाहरण के लिए (या किसी अन्य म्यूटेक्स) का उपयोग करता हूं, तो क्या यह ओपनएमपीआई और ओपेमएमपी जैसी अन्य समांतरता पुस्तकालयों के लिए कोड थ्रेड-सुरक्षित करेगा? या म्यूटेक्स विशेष रूप से लाइब्रेरी के समांतरता के लिए काम करता है जिसमें से म्यूटेक्स लिया जाता है? –

2

क्या यह काम करता है? क्या यह धागा सुरक्षित है?

नहीं। यह कई बार विफल हो जाएगा।

आपका म्युटेक्स केवल काम करेंगे अन्य थ्रेड इन दो पंक्तियों के निष्पादन के बीच कुछ भी कभी नहीं यदि:

if(!locked) 
{ 
    this->locked = 1; 

... और आप देखेंगे कि यह सुनिश्चित किया नहीं किया है।

के बारे में जानने के लिए mutex लेखन के, this SO post देखें।

2

नहीं, यह धागा सुरक्षित नहीं है।

myclass::add चल रहे दो धागे पर विचार करें, एक ही समय में कम या कम। साथ ही, कल्पना करें कि .locked का मान false है।

पहले धागा और इस लाइन सहित अप करने के लिए निष्पादित करता है:

if(!locked) 
{ 

अब कल्पना करें कि सिस्टम दूसरा धागा करने के लिए संदर्भ स्विच करता है। यह एक ही पंक्ति तक निष्पादित करता है।

अब हमारे पास दो अलग-अलग धागे हैं, दोनों का मानना ​​है कि उनके पास विशेष पहुंच है, और दोनों !locked की स्थिति में हैं।

वे दोनों vals.push_back() को एक ही समय में कम या कम से कम कॉल करेंगे।

बूम।

5

नहीं, यह धागा सुरक्षित नहीं है। वहाँ

if(!locked) 

और

this->locked = 1; 

यदि इन दो बयानों के बीच एक संदर्भ स्विच है के बीच एक दौड़ है, अपने लॉक तंत्र के अलावा गिर जाता है। आपको एक परमाणु test and set निर्देश की आवश्यकता है, या बस मौजूदा mutex का उपयोग करें।

5

यह कोड vals वेक्टर का परमाणु संशोधन प्रदान नहीं करता है। इस परिदृश्य पर विचार करें:

//<<< Suppose it's 0 
if(!locked) 
{ //<<< Thread 0 passes the check 
    //<<< Context Switch - and Thread 1 is also there because locked is 0 
    this->locked = 1; 
    //<<< Now it's possible for one thread to be scheduled when another one is in 
    //<<< the middle of modification of the vector 
    this->vals.push_back(val); 
    this->locked = 0; 
} 
1

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

आप जुओं से भरा हुआ किरकिरा में रुचि रखते हैं - आप Leslie Lamport's Bakery Algorithm को देखो और वहाँ से चले जाना चाहिए (या यहां तक ​​कि अगर तुम नहीं कर रहे हैं इस चीज हर सॉफ्टवेयर डेवलपर पता होना चाहिए है)।