मैं यह क्यों नहीं जांच सकता कि म्यूटेक्स लॉक है या नहीं?


28

C ++ 14 को लगता है कि एक std::mutexबंद है या नहीं , यह जांचने के लिए एक तंत्र छोड़ दिया है। इस SO प्रश्न को देखें:

https://stackoverflow.com/questions/21892934/how-to-assert-if-a-stdmutex-is-locked

इसके आसपास कई तरीके हैं, उदाहरण के लिए;

std::mutex::try_lock()
std::unique_lock::owns_lock()

लेकिन इनमें से कोई भी विशेष रूप से संतोषजनक समाधान नहीं हैं।

try_lock()यदि झूठे नकारात्मक को वापस करने की अनुमति है और अपरिभाषित व्यवहार किया जाता है यदि वर्तमान थ्रेड ने म्यूटेक्स को लॉक किया है। इसके साइड-इफेक्ट भी होते हैं। मूल के शीर्ष पर owns_lock()निर्माण की आवश्यकता है ।unique_lockstd::mutex

जाहिर है कि मैं अपना रोल कर सकता हूं, लेकिन मैं वर्तमान इंटरफेस के लिए प्रेरणाओं को समझूंगा।

एक म्यूटेक्स (जैसे std::mutex::is_locked()) की स्थिति की जांच करने की क्षमता मेरे लिए एक गूढ़ अनुरोध की तरह नहीं लगती है, इसलिए मुझे संदेह है कि मानक समिति ने जानबूझकर इस सुविधा को छोड़ दिया है क्योंकि यह एक निरीक्षण है।

क्यूं कर?

संपादित करें: ठीक है, इसलिए शायद यह प्रयोग मामला उतना सामान्य नहीं है जितना मैंने उम्मीद की थी, इसलिए मैं अपने विशेष परिदृश्य का वर्णन करूँगा। मेरे पास एक मशीन लर्निंग एल्गोरिदम है जो कई थ्रेड्स पर वितरित किया गया है। प्रत्येक थ्रेड एसिंक्रोनस रूप से काम करता है, और एक मास्टर पूल में लौटने के बाद एक अनुकूलन समस्या पूरी हो जाती है।

यह तब एक मास्टर म्यूटेक्स को लॉक करता है। थ्रेड को तब एक नया माता-पिता चुनना चाहिए, जिससे वंश उत्पन्न हो, लेकिन केवल उन माता-पिता से चुन सकते हैं, जिनके पास वर्तमान में ऐसी संतान नहीं है, जो अन्य धागों द्वारा अनुकूलित की जा रही हैं। इसलिए मुझे उन माता-पिता को खोजने के लिए एक खोज करने की आवश्यकता है जो वर्तमान में किसी अन्य धागे से बंद नहीं हैं। खोज के दौरान म्यूटेक्स की स्थिति का कोई खतरा नहीं है, क्योंकि मास्टर थ्रेड म्यूटेक्स लॉक है। जाहिर है कि अन्य समाधान हैं (मैं वर्तमान में बूलियन ध्वज का उपयोग कर रहा हूं) लेकिन मुझे लगा कि म्यूटेक्स इस समस्या का तार्किक समाधान प्रदान करता है, क्योंकि यह अंतर-थ्रेड सिंक्रोनाइज़ेशन के उद्देश्य से मौजूद है।


42
आप वास्तव में यथोचित जांच नहीं कर सकते हैं कि एक म्यूटेक्स लॉक है या नहीं, क्योंकि एक नैनोसेकंड चेक के बाद यह अनलॉक या लॉक हो सकता है। इसलिए यदि आपने "if (mutex_is_locked ()) ..." लिखा है तो mutex_is_locked सही परिणाम लौटा सकता है, लेकिन जब तक "यदि" निष्पादित होता है, तो यह गलत है।
gnasher729

1
इसमें ^। आप किस उपयोगी जानकारी से उम्मीद करते हैं is_locked?
बेकार

3
यह एक XY- समस्या की तरह लगता है। जब आप बच्चा पैदा कर रहे होते हैं तो केवल माता-पिता के पुन: उपयोग को रोकने की कोशिश क्यों कर रहे हैं? क्या आपके पास कोई आवश्यकता है कि किसी भी माता-पिता के पास केवल एक संतान हो सकती है? आपका लॉक ऐसा नहीं होने देगा। क्या आपके पास स्पष्ट पीढ़ियाँ नहीं हैं? यदि नहीं, तो क्या आप जानते हैं कि जिन व्यक्तियों को तेजी से अनुकूलित किया जा सकता है उनमें उच्च फिटनेस है, क्योंकि उन्हें अधिक बार / पहले चुना जा सकता है? यदि आप पीढ़ियों का उपयोग करते हैं, तो आप सभी माता-पिता को सामने क्यों नहीं चुनते हैं, तो धागे को एक कतार से माता-पिता को पुनः प्राप्त करने दें? क्या संतान पैदा करना इतना महंगा है कि आपको कई धागों की जरूरत है?
अमोन

10
@quant - मैं नहीं देखता कि आपके उदाहरण के आवेदन में आपके मूल ऑब्जेक्ट म्यूटेक्स को म्यूटेक्स होने की आवश्यकता क्यों है: यदि आपके पास एक मास्टर म्यूटेक्स है जो जब भी सेट किया जाता है, तो आप अपनी स्थिति को इंगित करने के लिए बूलियन चर का उपयोग कर सकते हैं।
14:12 बजे पेरीटा ब्रीटा

4
मैं प्रश्न के अंतिम वाक्य से असहमत हूं। यहाँ एक म्यूटेक्स की तुलना में एक साधारण बूलियन मूल्य बहुत साफ है। यदि आप माता-पिता को "लौटाने" के लिए मास्टर म्यूटेक्स को लॉक नहीं करना चाहते हैं तो इसे एक परमाणु बूल बनाएं।
सेबस्टियन रेडल

जवाबों:


53

मैं सुझाए गए ऑपरेशन के साथ कम से कम दो गंभीर समस्याएं देख सकता हूं।

पहले एक @ gnasher729 द्वारा टिप्पणी में पहले ही उल्लेख किया गया था :

आप वास्तव में यथोचित जांच नहीं कर सकते हैं कि एक म्यूटेक्स लॉक है या नहीं, क्योंकि एक नैनोसेकंड चेक के बाद यह अनलॉक या लॉक हो सकता है। इसलिए यदि आप लिखते हैं if (mutex_is_locked ()) …तो mutex_is_lockedसही परिणाम वापस कर सकते हैं, लेकिन जब तक ifइसे निष्पादित किया जाता है, यह गलत है।

यह सुनिश्चित करने का एकमात्र तरीका है कि किसी म्यूटेक्स की "वर्तमान में लॉक की गई संपत्ति" नहीं बदलती है, ठीक है, इसे स्वयं लॉक करें।

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

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

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


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

14
@ प्रश्न: यदि आपके पास माता-पिता को कतार में रखने के दो उद्देश्य हैं, तो आप दो कतारों के साथ ऐसा कर सकते हैं ....

@ क्वेंट: आप एक आइटम (एक बार में) को हटा रहे हैं, लेकिन संभवतः प्रत्येक कई बार प्रसंस्करण कर रहे हैं, इसलिए आप आम मामले की कीमत पर दुर्लभ मामले का अनुकूलन कर रहे हैं। यह शायद ही वांछनीय है।
जेरी कॉफिन

2
लेकिन यह है पूछने के लिए वर्तमान धागा म्युटेक्स बंद कर दिया गया है कि क्या उचित।
सीमित प्रायश्चित

@ सचलता नहीं वास्तव में। इस म्यूटेक्स को करने के लिए अतिरिक्त जानकारी (थ्रेड आईडी) को स्टोर करना पड़ता है, जिससे यह धीमा हो जाता है। पुनरावर्ती म्यूटेक्स पहले से ही ऐसा करते हैं, आपको इसके बजाय उन्हें करना चाहिए।
स्टेसीगर्ल

9

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

जो कि पूरी तरह से अनावश्यक है। मेरे पास समस्याओं की एक सूची होगी, जिनका अनुकूलन करने की आवश्यकता है, समस्याओं की एक सूची अभी अनुकूलित की जा रही है, और उन समस्याओं की एक सूची जिन्हें अनुकूलित किया गया है। ("सूची" को शाब्दिक रूप से न लें, इसका अर्थ "किसी भी उपयुक्त डेटा संरचना से लें)"।

अडॉप्टेड समस्याओं की सूची में एक नई समस्या को जोड़ने, या किसी समस्या को एक सूची से दूसरी में ले जाने के संचालन, एकल "मास्टर" म्यूटेक्स के संरक्षण में किया जाएगा।


1
आपको नहीं लगता कि std::mutexइस तरह की डेटा संरचना के लिए ऑब्जेक्ट का प्रकार उपयुक्त है?
क्वांट

2
@ उत्तर - नहीं। std::mutexएक ऑपरेटिंग-सिस्टम परिभाषित म्यूटेक्स कार्यान्वयन पर निर्भर करता है जो संसाधनों (जैसे हैंडल) को ले सकता है जो कि आवंटित और / या संचालित करने के लिए सीमित और धीमा हैं। आंतरिक डेटा संरचना तक पहुंच को लॉक करने के लिए एकल म्यूटेक्स का उपयोग करना अधिक कुशल होने की संभावना है, और संभवतः अधिक स्केलेबल भी है।
पेरियाटा ब्रीटा

1
इसके अलावा हालत चर पर विचार करें। वे इस तरह के डेटा संरचनाओं को वास्तव में आसान बना सकते हैं।
Cort Ammon - मोनिका

2

जैसा कि दूसरों ने कहा, is_lockedम्यूटेक्स पर कोई फायदा नहीं है, जहां कोई फायदा नहीं है, इसलिए फ़ंक्शन मौजूद नहीं है।

आप जिस समस्या से जूझ रहे हैं, वह अविश्वसनीय रूप से आम है, यह मूल रूप से श्रमिक सूत्र क्या करते हैं, जो कि थ्रेड्स का सबसे सामान्य कार्यान्वयन नहीं है

आपके पास उस पर 10 बक्से के साथ एक शेल्फ है। आपके पास इन बॉक्स के साथ काम करने वाले 4 कर्मचारी हैं। आप यह सुनिश्चित कैसे कर सकते हैं कि 4 श्रमिक विभिन्न बक्सों पर काम करते हैं? पहले कार्यकर्ता शेल्फ पर एक बॉक्स लेते हैं, इससे पहले कि वे उस पर काम करना शुरू कर दें। दूसरा कार्यकर्ता शेल्फ पर 9 बक्से देखता है।

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


1

ऊपर दिए गए 5gon12eder के उत्तर में दिए गए दो कारणों के अलावा, मैं यह जोड़ना चाहूंगा कि यह न तो आवश्यक है और न ही वांछनीय है।

यदि आप पहले से ही म्यूटेक्स धारण कर रहे हैं, तो आपको बेहतर पता था कि आप इसे पकड़ रहे हैं! आपको पूछने की जरूरत नहीं है। जैसे स्मृति या किसी अन्य संसाधन के ब्लॉक के मालिक होने के साथ, आपको यह जानना चाहिए कि क्या आप इसके मालिक हैं या नहीं, और जब यह संसाधन को जारी करने / हटाने के लिए उपयुक्त हो।
यदि ऐसा नहीं है, तो आपका कार्यक्रम बुरी तरह से डिज़ाइन किया गया है, और आप परेशानी की ओर बढ़ रहे हैं।

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

हर दूसरे मामले में, निस्संदेह, यह आपके व्यवसाय में से कोई भी नहीं है। आपको जानने की आवश्यकता नहीं है, और आपको पता नहीं होना चाहिए, या मान्यताओं (अन्य प्रश्न में उल्लिखित समयबद्धता और सिंक मुद्दों के लिए) करना चाहिए।


1
क्या होगा यदि मैं उन संसाधनों पर रैंकिंग ऑपरेशन करना चाहता हूं जो वर्तमान में लॉकिंग के लिए उपलब्ध हैं?
क्वांट

लेकिन क्या ऐसा कुछ होना वास्तविक है? मुझे लगता है कि असामान्य है। मैं कहूंगा कि या तो संसाधनों में पहले से ही कुछ आंतरिक प्रकार की रैंकिंग है, फिर आपको पहले अधिक महत्वपूर्ण कार्य करना होगा (लॉक के लिए अधिग्रहण करना होगा)। उदाहरण: प्रतिपादन करने से पहले भौतिकी सिमुलेशन को अद्यतन करना चाहिए। या, रैंकिंग कम या ज्यादा जानबूझकर है, तो आप try_lockपहले संसाधन के रूप में अच्छी तरह से कर सकते हैं , और यदि वह विफल रहता है, तो दूसरा प्रयास करें। उदाहरण: डेटाबेस सर्वर से तीन लगातार, पूल किए गए कनेक्शन और आपको कमांड भेजने के लिए एक का उपयोग करने की आवश्यकता है।
डेमन

4
@quant - "उन संसाधनों पर एक रैंकिंग ऑपरेशन जो वर्तमान में लॉकिंग के लिए उपलब्ध हैं" - सामान्य तौर पर, कोड को लिखने के लिए इस तरह की बात करना वास्तव में आसान और त्वरित तरीका है कि एक तरह से गतिरोध का पता लगाने के लिए आप संघर्ष करते हैं। तालों का अधिग्रहण और निर्धारक निर्धारण , लगभग सभी मामलों में, सबसे अच्छी नीति है। कसौटी के आधार पर लॉक की खोज जो बदल सकती है वह परेशानी पूछ रही है।
पेरियाटा ब्रीटा

@PeriataBreatta मेरा कार्यक्रम जानबूझकर अनिश्चित है। मैं अब देख रहा हूं कि यह विशेषता सामान्य नहीं है, इसलिए मैं is_locked()इस तरह के व्यवहार की सुविधा को समझ सकता हूं, जिससे इस तरह के व्यवहार की सुविधा मिल सके।
क्वांट

@ निरंतर रैंकिंग और लॉकिंग पूरी तरह से अलग समस्याएं हैं। यदि आप किसी तरह से एक कतार के साथ किसी प्रकार को सॉर्ट करना या फिर से लिखना चाहते हैं, तो इसे लॉक करें, इसे सॉर्ट करें, फिर इसे अनलॉक करें। यदि आपको आवश्यकता है is_locked, तो आपकी समस्या का एक बेहतर समाधान आपके पास मौजूद मन से मौजूद है।
पीटर

1

आप डिफ़ॉल्ट मेमोरी ऑर्डर के साथ परमाणु_फ्लैग का उपयोग करना चाह सकते हैं । इसमें डेटा दौड़ नहीं है और कभी भी अपवाद नहीं फेंकता है जैसे म्यूटेक्स कई अनलॉक कॉल के साथ करता है (और अनियंत्रित रूप से गर्भपात करता है, मैं जोड़ सकता हूं ...)। वैकल्पिक रूप से, परमाणु (जैसे परमाणु [बूल] या परमाणु [int] (त्रिकोण कोष्ठक के साथ, नहीं [])) है, जिसमें लोड और तुलना_एक्सचेंज_स्ट्रोंग जैसे अच्छे कार्य हैं।


1

मैं इसके लिए एक उपयोग-मामला जोड़ना चाहता हूं: यह एक आंतरिक कार्य को एक पूर्व शर्त / जोर के रूप में सुनिश्चित करने में सक्षम करेगा कि कॉलर वास्तव में लॉक को पकड़े हुए है।

ऐसे कई आंतरिक कार्यों वाले वर्गों के लिए, और संभवतः उन्हें कॉल करने वाले कई सार्वजनिक फ़ंक्शंस, यह सुनिश्चित कर सकते हैं कि कोई व्यक्ति किसी अन्य सार्वजनिक फ़ंक्शन को जोड़ रहा है जो आंतरिक कॉल कर रहा है, वास्तव में लॉक का अधिग्रहण किया है।

class SynchronizedClass
{

public:

void publicFunc()
{
  std::lock_guard<std::mutex>(_mutex);

  internalFuncA();
}

// A lot of code

void newPublicFunc()
{
  internalFuncA(); // whops, forgot to acquire the lock
}


private:

void internalFuncA()
{
  assert(_mutex.is_locked_by_this_thread());

  doStuffWithLockedResource();
}

};
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.