2012-10-27 17 views
62

मैं जब std::condition_variable के साथ काम करने में थोड़ा std::unique_lock की भूमिका के बारे उलझन में हूँ। जहां तक ​​मुझे documentation समझा गया, std::unique_lock मूल रूप से एक ब्लॉटेड लॉक गार्ड है, जिसमें दो ताले के बीच राज्य को स्वैप करने की संभावना है।सी ++ 11: std :: condition_variable std :: unique_lock का उपयोग क्यों करता है?

मैं अब तक इस उद्देश्य (मुझे लगता है कि क्या एसटीएल POSIX पर उपयोग करता है) के लिए pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) का उपयोग किया है। यह एक म्यूटक्स लेता है, लॉक नहीं।

क्या फर्क यहाँ है? क्या यह तथ्य है कि std::condition_variablestd::unique_lock के साथ एक अनुकूलन है? यदि हां, तो यह कितनी तेजी से है?

+2

क्या आप इस बारे में उलझन में हैं कि आपको एक कंडीशन वैरिएबल के साथ लॉक/म्यूटेक्स की आवश्यकता क्यों है, या लॉक और म्यूटेक्स के बीच के अंतर के बारे में या क्यों एक कंडीशन वेरिएबल एक अद्वितीय लॉक का उपयोग करता है और म्यूटेक्स नहीं? – Brady

+0

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

उत्तर

91

इसलिए कोई तकनीकी कारण क्या है?

मैंने cmeerw के उत्तर को ऊपर उठाया क्योंकि मुझे विश्वास है कि उसने तकनीकी कारण दिया है। चलो इसके माध्यम से चलते हैं। आइए दिखाएं कि समिति ने condition_variablemutex पर प्रतीक्षा करने का निर्णय लिया था। यहाँ है कि डिजाइन का उपयोग कर कोड है:

void foo() 
{ 
    mut.lock(); 
    // mut locked by this thread here 
    while (not_ready) 
     cv.wait(mut); 
    // mut locked by this thread here 
    mut.unlock(); 
} 

यह ठीक है कि कैसे एक एक condition_variable उपयोग नहीं करना चाहिए। क्षेत्रों के साथ चिह्नित क्षेत्रों में:

// mut locked by this thread here 

एक अपवाद सुरक्षा समस्या है, और यह एक गंभीर है। यदि इन क्षेत्रों में एक अपवाद फेंक दिया गया है (या cv.wait स्वयं), तो म्यूटेक्स की लॉक स्थिति तब तक लीक हो जाती है जब तक कि अपवाद को पकड़ने और इसे अनलॉक करने के लिए कहीं भी प्रयास/पकड़ न रखा जाए। लेकिन यह सिर्फ इतना कोड है कि आप प्रोग्रामर को लिखने के लिए कह रहे हैं।

मान लें कि प्रोग्रामर जानता है कि अपवाद सुरक्षित कोड कैसे लिखना है, और इसे प्राप्त करने के लिए unique_lock का उपयोग करना जानता है। अब कोड इस तरह दिखता है:

void foo() 
{ 
    unique_lock<mutex> lk(mut); 
    // mut locked by this thread here 
    while (not_ready) 
     cv.wait(*lk.mutex()); 
    // mut locked by this thread here 
} 

यह बहुत बेहतर है, लेकिन यह अभी भी एक अच्छी स्थिति नहीं है। condition_variable इंटरफ़ेस प्रोग्रामर को काम करने के लिए अपने रास्ते से बाहर निकल रहा है। lk गलती से एक mutex का संदर्भ नहीं देता है तो एक संभावित शून्य सूचक dereference है। और यह देखने के लिए condition_variable::wait के लिए कोई रास्ता नहीं है कि यह थ्रेड mut पर लॉक का मालिक है।

ओह, बस याद किया गया है कि प्रोग्रामर गलत है unique_lock सदस्य फ़ंक्शन mutex का पर्दाफाश करने के लिए चुन सकता है। यहां विनाशकारी होगा।

अब कैसे कोड वास्तविक condition_variable एपीआई कि एक unique_lock<mutex> लेता है के साथ लिखा है पर ध्यान दें:

void foo() 
{ 
    unique_lock<mutex> lk(mut); 
    // mut locked by this thread here 
    while (not_ready) 
     cv.wait(lk); 
    // mut locked by this thread here 
} 
  1. इस कोड के रूप में सरल रूप में यह मिल सकता है।
  2. यह अपवाद सुरक्षित है।
  3. wait फ़ंक्शन lk.owns_lock() देख सकता है और false पर अपवाद फेंक सकता है।

ये तकनीकी कारण हैं जो condition_variable के एपीआई डिज़ाइन को चलाते हैं।

साथ ही, condition_variable::wait नहीं ले एक क्योंकि lock_guard<mutex>lock_guard<mutex> आप कैसे कहते हैं है है: मैं lock_guard<mutex> नष्ट हो जब तक इस म्युटेक्स पर ताला के मालिक हैं। लेकिन जब आप condition_variable::wait पर कॉल करते हैं, तो आप पूरी तरह से म्यूटेक्स पर लॉक जारी करते हैं। ताकि कार्रवाई lock_guard उपयोग केस/कथन के साथ असंगत है।

हम इतना है कि एक, कार्यों से ताले लौट सकते हैं उन्हें कंटेनर में डाल दिया, और लॉक/एक अपवाद सुरक्षित तरीके से गैर-दायरे वाले पैटर्न में mutexes अनलॉक, तो unique_lockcondition_variable::wait के लिए स्वाभाविक पसंद था वैसे भी unique_lock की जरूरत है।

अद्यतन

bamboon है कि मैं इसके विपरीत condition_variable_any नीचे टिप्पणी में सुझाव दिया है, इसलिए यहाँ जाता है:

प्रश्न: क्यों टेम्प्लेट नहीं condition_variable::wait जाता है जिससे कि मैं इसे करने के लिए कोई Lockable प्रकार पारित कर सकते हैं ?

उत्तर:

यह वास्तव में करने के लिए शांत कार्यक्षमता है। उदाहरण के लिए this paper कोड को प्रदर्शित करता है जो shared_lock (rwlock) पर एक साझा चर पर साझा मोड में प्रतीक्षा करता है (पॉज़िक्स दुनिया में कुछ अनदेखा है, लेकिन फिर भी बहुत उपयोगी है)। हालांकि कार्यक्षमता अधिक महंगा है।

तो समिति इस कार्यक्षमता के साथ एक नए प्रकार की शुरुआत की:

`condition_variable_any` 

इस condition_variableएडाप्टर एक साथ किसी भी ताला-युक्त प्रकार पर इंतजार कर सकते हैं। यदि इसमें lock() और unlock() सदस्य हैं, तो आप जाने के लिए अच्छे हैं। condition_variable_any का एक उचित कार्यान्वयन condition_variable डेटा सदस्य और shared_ptr<mutex> डेटा सदस्य की आवश्यकता है।

क्योंकि यह नई कार्यक्षमता आपके मूल condition_variable::wait से अधिक महंगी है, और क्योंकि condition_variable इतना निम्न स्तर का टूल है, यह बहुत उपयोगी लेकिन अधिक महंगी कार्यक्षमता एक अलग वर्ग में डाल दी गई थी ताकि आप इसका उपयोग केवल इसके लिए ही कर सकें ।

+0

क्या आप इसे "स्पष्ट" कर सकते हैं। क्या आप 'lock_guard', या' condition_variable', या शायद 'condition_variable :: wait' के बारे में बात कर रहे हैं? –

+0

क्षमा करें, इसे भूल जाओ। मैं पूरी तरह से 'condition_variable_any' – inf

+0

आह, टेम्पलेट 'condition_variable :: प्रतीक्षा' के बारे में भूल गया। हां, 'condition_variable_any' जाने का रास्ता है। और कारण यह है कि कार्यक्षमता 'condition_variable' में नहीं जुड़ी है यह है कि यह अधिक महंगा है। और 'condition_variable' इतना निम्न स्तर का टूल है, इसे ऐसा कुछ होना आवश्यक है जो जितना संभव हो उतना कुशल हो। यदि आप 'condition_variable_any' का उपयोग करते हैं तो आप केवल अतिरिक्त कार्यक्षमता के लिए भुगतान करते हैं। –

32

यह अनिवार्य संभव के रूप में एपीआई के रूप में सुरक्षित (अतिरिक्त भूमि के ऊपर के साथ के रूप में देखा जा रहा है नगण्य) डिफ़ॉल्ट रूप से बनाने के लिए एक API डिजाइन निर्णय है। एपीआई के कच्चे mutex उपयोगकर्ताओं के बजाय unique_lock पास करने की आवश्यकता के अनुसार सही कोड (अपवादों की उपस्थिति में) लिखने के लिए निर्देशित किया जाता है।

हाल के वर्षों में सी ++ भाषा का ध्यान केंद्रित यह डिफ़ॉल्ट रूप से सुरक्षित बनाने (लेकिन अभी भी उपयोगकर्ताओं को अपने पैरों में खुद को गोली मार करने की इजाजत दी है अगर वे चाहते हैं और कठिन पर्याप्त कोशिश) की ओर स्थानांतरित हो गया है।

+0

तो कोई तकनीकी कारण नहीं है? –

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