2016-09-07 19 views
14

संकलक बस की जाँच करता है जो चर ताला के बीच संशोधित किया जा रहा है और बयानों अनलॉक और उन्हें म्युटेक्स करने के लिए बाध्य तो वहाँ उन्हें विशेष उपयोग कर सकते है?सी ++ std :: mutex संसाधन से कैसे जुड़ता है?

या एक mutex.lock() सभी संसाधनों जो वर्तमान क्षेत्र में दिखाई दे रहे लॉक करता है?

+13

mutex किसी भी चर को लॉक नहीं करता है, यह केवल उस धागे को अवरुद्ध करता है जो इसे प्राप्त करने का प्रयास कर रहा है।यदि वे प्रोग्राम केवल 'लॉक()' और 'अनलॉक()' कॉल के बीच पहुंचता है तो इसका चर बदलने की प्रभाव पड़ती है। कोड में म्यूटेक्स 'लॉक()' और 'अनलॉक() 'की मौजूदगी भी कंपाइलर को चर * एक्सेस * की स्मृति मेमोरी एक्सेस को फिर से ऑर्डर करने से रोकती है। –

+3

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

+0

धन्यवाद, यह वास्तव में इसे मंजूरी दे दी! – niko

उत्तर

15

यह देखते हुए कि m प्रकार std::mutex की एक चर रहा है:

ख से एक का काम:

int a; 
m.lock(); 
b += 1; 
a = b; 
m.unlock(); 
do_something_with(a); 

वहाँ पर यहाँ जा रहा एक 'स्पष्ट' बात यह है:

इस क्रम कल्पना कीजिए और ख की वेतन वृद्धि अन्य धागे से हस्तक्षेप से 'सुरक्षित' है, क्योंकि अन्य थ्रेड एक ही m लॉक करने के लिए जब तक हम m.unlock() फोन का प्रयास करेंगे और अवरुद्ध हो जाएगा।

और एक और सूक्ष्म चीज चल रही है।

सिंगल-थ्रेडेड कोड में, कंपाइलर लोड और स्टोर्स को फिर से ऑर्डर करना चाहता है।

int a = b + 1; 
// m.lock(); 
b = a; 
// m.unlock(); 
do_something_with(a); 

या भी:

do_something_with(++b); 

हालांकि, std::mutex::lock(), unlock() ताले बिना, संकलक प्रभावी रूप से अपने कोड को फिर से लिखना करने के लिए स्वतंत्र है कि अगर यह पता चला अपने चिपसेट पर अधिक कुशल होने का होगा , std::thread(), std::async(), std::future::get() और इसी तरह बाड़ हैं। कंपाइलर 'जानता है' कि यह लोड और स्टोर्स (पढ़ता है और लिखता है) इस तरह से पुन: व्यवस्थित नहीं कर सकता है कि ऑपरेशन बाड़ के दूसरी तरफ समाप्त होता है जहां से आपने कोड लिखा था।

1: 
2: m.lock(); <--- This is a fence 
3: b += 1; <--- So this load/store operation may not move above line 2 
4: m.unlock(); <-- Nor may it be moved below this line 

कल्पना कीजिए कि अगर मामला यह नहीं था क्या होगा:

(पुनर्क्रमित कोड)

thread1: int a = b + 1; 
    <--- Here another thread precedes us and executes the same block of code 
    thread2: int a = b + 1; 
    thread2: m.lock(); 
    thread2: b = a; 
    thread2: m.unlock(); 
thread1: m.lock(); 
thread1: b = a; 
thread1: m.unlock(); 
thread1:do_something_with(a); 
thread2:do_something_with(a); 

आप इसे माध्यम से पालन करें, तो आप देखेंगे कि ख अब गलत है इसमें मूल्य, क्योंकि संकलक आपके कोड को तेज़ी से बनाने के लिए तैयार था।

... और यह केवल संकलक अनुकूलन है। std::mutex, इत्यादि मेमोरी कैश को एक अधिक 'इष्टतम' तरीके से रीडरिंग लोड और स्टोर्स से रोकता है, जो एकल-थ्रेडेड वातावरण में ठीक होगा लेकिन बहु-कोर (यानी कोई आधुनिक पीसी या फोन) सिस्टम में विनाशकारी होगा।

इस सुरक्षा के लिए एक लागत है, क्योंकि थ्रेड ए के कैश को उसी डेटा को पढ़ने से पहले फ़्लश किया जाना चाहिए, और कैश मेमोरी एक्सेस की तुलना में स्मृति में कैश फ्लश करना धीमा है। लेकिन सीएस्ट ला वी। समवर्ती निष्पादन को सुरक्षित करने का यही एकमात्र तरीका है।

यही कारण है कि हम एक एसएमपी प्रणाली में, यदि संभव हो, तो पसंद करते हैं, प्रत्येक थ्रेड में डेटा की अपनी प्रतिलिपि होती है जिस पर काम करना है। हम न केवल लॉक में बिताए गए समय को कम करना चाहते हैं, बल्कि कई बार बाड़ पार करते हैं।

मैं std::memory_order संशोधक के बारे में बात करने के लिए जा सकते हैं, लेकिन यह एक अंधेरे और खतरनाक छेद है, जो विशेषज्ञों अक्सर गलत और जिसमें शुरुआती यह सही हो रही है की कोई आशा नहीं है।

+4

आपकी आखिरी वाक्य एक अल्पमत है। :) – Mysticial

1

संसाधन उपयोग के संदर्भ में, संकलक कम के बारे में mutex.lock() परवाह नहीं कर सका। यह प्रोग्रामर ड्यूटी यह सुनिश्चित करने के लिए है कि संसाधन लॉक उचित लॉकिंग/अनलॉकिंग के भीतर हो रहा है।

हालांकि, कंपाइलर इस तरह से एक म्यूटेक्स की परवाह करता है कि यह जानता है कि कुछ संरचनाओं को अनुकूलित करने के लिए यह अन्यथा नहीं है - लेकिन आप शायद इस समय में रुचि नहीं रखते हैं।

6

"म्युटेक्स" "पारस्परिक अपवर्जन" का संक्षिप्त रूप है, एक म्युटेक्स प्रयोग करने के लिए उचित अनुशासन किसी भी कोड है कि चर धागे के बीच और इसे अनलॉक करने के लिए जब कोड के उस अनुभाग से किया जाता है साझा कर रहे हैं कि संशोधित करता है प्रवेश करने से पहले यह लॉक करने के लिए है। यदि एक थ्रेड म्यूटेक्स को लॉक करता है, तो कोई अन्य थ्रेड जो इसे लॉक करने का प्रयास करता है उसे तब तक अवरुद्ध कर दिया जाएगा जब तक कि mutex के थ्रेड को अनलॉक नहीं किया जाता है। इसका मतलब है कि एक समय में केवल एक थ्रेड कोड के अंदर है जो साझा चर को संशोधित कर सकता है, और यह दौड़ की स्थिति को समाप्त करता है।

कुछ म्यूटेक्स कुछ स्तर पर कंपाइलर जादू पर निर्भर करता है: यह संकलक को सुरक्षित कोड के अंदर से डेटा के लोड और स्टोर्स को आगे बढ़ने से रोकता है, और इसके विपरीत, जो संरक्षित के लिए जरूरी है संरक्षित रहने के लिए कोड।

3

एक म्युटेक्स एक semaphore की एक विशेष कार्यान्वयन है। विशेष रूप से यह एक द्विआधारी सेमाफोर है।

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

int mutex = 1; // The mutex is free when created (free=1, occupied=0). 

// in a concurrency block 
{ 
    :try-again 

    // test if mutex is 1 (is free). 
    if (mutex > 0) { 

    // mutex WAS free so now I set as occupied (set 0) 
    --mutex; 
    // Now I've 'acquired' the mutex and since the mutex is 0 or 1 
    // only me can be here. 

    // Do something in mutual exclusion 
    // Done. 
    // Unlock the mutex 
    ++mutex; 
    // Now the mutex is free so other threads can acquire it. 

    } else { 
    // Mutex is 0 so I tried but it's already occupied. 
    // Block the thread and try again. 
    goto try-again; 
    } 

} 

स्पष्ट, कि दृष्टिकोण काम नहीं कर सकता, क्योंकि एक धागा बाधित किया जा सकता है के बाद यह म्युटेक्स है परीक्षण किया गया है:

(छद्म hight स्तर कोड) की तरह कुछ कल्पना कीजिए मुक्त और इससे पहले कि इसे कब्जा कर लिया जा सके।

कारण है कि सेमाफोर और इतने म्युटेक्स आदिम निर्देश की सहायता जो उन "परीक्षण और सेट" "एक घड़ी" (atomically) में ऑपरेशन को लागू के साथ लागू कर रहे हैं के लिए

एक उदाहरण test-and-set आदिम है।

+0

क्योंकि मुझे म्यूटेक्स और बाइनरी सेमफोर का इलाज करके परिवर्तनीय के रूप में जला दिया गया है, इसमें एक अंतर है। कई थ्रेडिंग लाइब्रेरीज़ (जैसे कि पर्थ्रेड) में, एक म्यूटेक्स केवल उस थ्रेड द्वारा अनलॉक किया जा सकता है जो इसे बंद कर देता है, जबकि किसी भी थ्रेड द्वारा सेमफोर को "अनलॉक" किया जा सकता है। –

3

इस तरह की कोई चतुरता नहीं है, और इसे सही ढंग से काम करने के लिए प्रोग्रामर की ज़िम्मेदारी है।

एक म्यूटेक्स ऐसे घर पर लॉक करने योग्य दरवाजे की तरह है जिसमें दीवार नहीं है।

आप इसके साथ कर सकते हैं अन्य लोगों को दरवाजा के माध्यम से लॉक होने पर घर में प्रवेश करने से रोकता है।
दरवाजा केवल तभी उपयोगी होता है जब हर कोई दरवाजे के माध्यम से घर में प्रवेश करने के लिए सहमत हो, और जब दरवाजा बंद हो जाता है तो दरवाजे को बाहर निकलने और बाहर निकलने के लिए अंदर की प्रतीक्षा करें।
किसी भी बुरे व्यक्ति को उस समझौते को छोड़कर गैर-विद्यमान दीवारों के माध्यम से घर में प्रवेश करने से मना कर दिया गया है जो आपको नहीं करना चाहिए।

+1

चतुरता इस तथ्य में है कि संकलक के अनुकूलक और कोड जनरेटर अंतर्निहित स्मृति बाड़ को पहचानते हैं और सम्मान करते हैं। –

+0

कभी भी ध्यान न रखें कि दीवारों के बिना आपके पास घर का बहुत अधिक हिस्सा नहीं है। – immibis

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