म्यूटेक्स को लॉक किए बिना pthread_cond_signal को कॉल करना


85

मैंने कहीं पढ़ा है कि हमें pthread_cond_signal को कॉल करने से पहले म्यूटेक्स को लॉक करना चाहिए और कॉल करने के लिए म्यूटेक्स को अनलॉक करना चाहिए :

Pthread_cond_signal () रूटीन का उपयोग एक अन्य सूत्र को संकेत देने (या जागने) के लिए किया जाता है जो स्थिति चर पर प्रतीक्षा कर रहा है। म्यूटेक्स बंद होने के बाद इसे कॉल किया जाना चाहिए, और म्यूटेक्स को pthread_cond_wait () को पूरा करने के लिए रूटीन को अनलॉक करना होगा।

मेरा सवाल यह है कि क्या mutex को लॉक किए बिना pthread_cond_signal या pthread_cond_broadcast तरीकों को कॉल करना ठीक नहीं है ?

जवाबों:


143

यदि आप कोडपथ में म्यूटेक्स को लॉक नहीं करते हैं जो स्थिति और संकेतों को बदलता है, तो आप वेकअप खो सकते हैं। प्रक्रियाओं की इस जोड़ी पर विचार करें:

प्रक्रिया A:

pthread_mutex_lock(&mutex);
while (condition == FALSE)
    pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);

प्रक्रिया बी (गलत):

condition = TRUE;
pthread_cond_signal(&cond);

फिर निर्देशों के इस संभावित इंटरलेविंग पर विचार करें, जहां conditionशुरू होता है FALSE:

Process A                             Process B

pthread_mutex_lock(&mutex);
while (condition == FALSE)

                                      condition = TRUE;
                                      pthread_cond_signal(&cond);

pthread_cond_wait(&cond, &mutex);

conditionअब है TRUE, लेकिन प्रक्रिया एक शर्त चर पर अटक प्रतीक्षा है - यह Wakeup संकेत याद किया। यदि हम म्यूटेक्स को लॉक करने के लिए प्रोसेस बी को बदलते हैं:

प्रक्रिया बी (सही):

pthread_mutex_lock(&mutex);
condition = TRUE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);

... तो ऊपर नहीं हो सकता; वेकअप कभी नहीं छूटेगा।

(ध्यान दें कि आप वास्तव में खुद को स्थानांतरित कर सकते हैं , लेकिन इसके परिणामस्वरूप थ्रेड्स का कम इष्टतम निर्धारण हो सकता है, और आपने आवश्यक रूप से स्थिति बदलने के कारण इस कोड पथ में पहले से ही म्यूटेक्स को लॉक कर दिया है)।pthread_cond_signal()pthread_mutex_unlock()


4
@ नीमो: हाँ, "सही" पथ में म्यूटेक्स अनलॉक के बाद ले जाया pthread_signal_cond() जा सकता है, हालांकि यह शायद बेहतर नहीं है। यह कहना अधिक सही है कि जिस बिंदु पर आप कॉल कर रहे हैं pthread_signal_cond(), उस स्थिति को संशोधित करने के लिए आपको पहले से ही म्यूटेक्स को लॉक करना होगा।
कैफे

@ नीमो: हाँ, कोड टूट गया है, यही कारण है कि इसे "गलत" के रूप में चिह्नित किया गया है - यह मेरा अनुभव है कि जो लोग यह सवाल पूछ रहे हैं वे अक्सर सिग्नलिंग पथ पर पूरी तरह से लॉकिंग छोड़ने पर विचार कर रहे हैं। शायद आपका अनुभव अलग हो।
कैफे

10
इसके लायक होने के लिए, यह सवाल लगता है कि संकेत से पहले या बाद में अनलॉक करना है या नहीं, जवाब देने के लिए वास्तव में गैर-तुच्छ है। अनलॉक करने के बाद यह सुनिश्चित होता है कि निम्न-प्राथमिकता वाला धागा ईवेंट को उच्च-प्राथमिकता वाले से चुरा नहीं पाएगा, लेकिन यदि आप प्राथमिकताओं का उपयोग नहीं कर रहे हैं, तो सिग्नल से पहले अनलॉक करने से वास्तव में सिस्टम कॉल / संदर्भ स्विच की संख्या कम हो जाएगी और समग्र प्रदर्शन में सुधार।
R .. GitHub STOP हेल्पिंग ICE

1
@ आर .. आपके पास यह पीछे की ओर है। सिग्नल से पहले अनलॉक करना सिस्टम कॉल की संख्या को बढ़ाता है और समग्र प्रदर्शन को कम करता है। यदि आप अनलॉक करने से पहले संकेत देते हैं, तो कार्यान्वयन जानता है कि संकेत संभवतः एक धागा नहीं जगा सकता है (क्योंकि आगे बढ़ने के लिए cv पर अवरुद्ध किसी भी धागे को म्यूटेक्स की आवश्यकता है), जिससे वह तेज़ पथ का उपयोग कर सके। यदि आप अनलॉक के बाद संकेत देते हैं, तो दोनों अनलॉक और सिग्नल थ्रेड को जगा सकते हैं, जिसका अर्थ है कि वे दोनों महंगे ऑपरेशन हैं।
डेविड श्वार्ट्ज

1
@Alceste_: में इस पाठ देखें POSIX : एक शर्त चर पर एक धागा प्रतीक्षा करता है, या तो के लिए एक विशेष म्युटेक्स निर्दिष्ट करने के जब " pthread_cond_timedwait()या pthread_cond_wait()आपरेशन, एक गतिशील बंधन कि म्युटेक्स और हालत चर के बीच बनाई है कि लंबे समय के रूप में के रूप में प्रभाव में रहता है शर्त चर पर कम से कम एक धागा अवरुद्ध होता है। इस समय के दौरान, किसी भी धागे द्वारा किसी भिन्न म्यूटेक्स का उपयोग करके प्रतीक्षा करने के प्रयास का प्रभाव अपरिभाषित होता है। "
कैफे

51

इस मैनुअल के अनुसार:

pthread_cond_broadcast()या pthread_cond_signal() कार्यों एक धागा है या नहीं, यह वर्तमान में म्युटेक्स मालिक द्वारा कहा जा सकता है कि धागे बुला pthread_cond_wait() या pthread_cond_timedwait()उनकी प्रतीक्षा करता दौरान हालत चर से संबद्ध कर दिया है; हालाँकि, यदि पूर्वानुमेय शेड्यूलिंग व्यवहार की आवश्यकता है, तो उस म्यूटेक्स को थ्रेड कॉलिंग द्वारा लॉक किया जाएगा pthread_cond_broadcast()या pthread_cond_signal()

डेव ब्यूटेनहोफ ( POSIX थ्रेड्स के साथ प्रोग्रामिंग के लेखक ) द्वारा comp.programming.threads पर अनुमानित समय-निर्धारण व्यवहार कथन का अर्थ समझाया गया था और यहां उपलब्ध है


6
डेव ब्यूटेनहोफ के मेल को लिंक करने के लिए +1। मैं हमेशा इस मुद्दे के बारे में सोचता था, अब मुझे पता है ... आज कुछ महत्वपूर्ण सीखा। धन्यवाद।
निल्स पिपेनब्रिनक

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

7

आपके नमूना कोड में कैफ़े, प्रोसेस बी conditionपहले म्यूटेक्स को लॉक किए बिना संशोधित करता है । यदि प्रक्रिया B ने केवल उस संशोधन के दौरान म्यूटेक्स को बंद कर दिया, और फिर भी कॉल करने से पहले म्यूटेक्स को अनलॉक किया pthread_cond_signal, तो कोई समस्या नहीं होगी --- क्या मैं इसके बारे में सही हूं?

मैं सहजता से मानता हूं कि कैफे की स्थिति सही है: pthread_cond_signalम्यूटेक्स लॉक के मालिक के बिना कॉल करना एक बुरा विचार है। लेकिन कैफे का उदाहरण वास्तव में इस स्थिति के समर्थन में सबूत नहीं है; यह केवल बहुत कमजोर (व्यावहारिक रूप से आत्म-स्पष्ट) स्थिति के समर्थन में सबूत है कि यह एक म्यूटेक्स द्वारा संरक्षित साझा स्थिति को संशोधित करने के लिए एक खराब विचार है जब तक कि आपने उस म्यूटेक्स को पहले बंद नहीं किया है।

क्या कोई नमूना कोड प्रदान कर सकता है जिसमें कॉल करने के pthread_cond_signalबाद pthread_mutex_unlockपैदावार का सही व्यवहार होता है, लेकिन pthread_mutex_unlockइसके बाद कॉल करने pthread_cond_signalसे गलत व्यवहार होता है?


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

मैंने अपने उत्तर के अंतिम पैराग्राफ में यह अवलोकन किया।
कैफे

आपके पास यहां एक अच्छा परिदृश्य है: stackoverflow.com/a/6419626/1284631 ध्यान दें कि यह दावा नहीं करता है कि व्यवहार गलत है, यह केवल एक मामला प्रस्तुत करता है जहां व्यवहार अपेक्षा के अनुरूप नहीं हो सकता है।
user1284631

नमूना कोड बनाना संभव है, जहां कॉल करने के pthread_cond_signalबाद pthread_mutex_unlockएक खोया हुआ वेकअप हो सकता है क्योंकि सिग्नल को "गलत" धागा पकड़ा जाता है, जो कि विधेय में परिवर्तन को देखने के बाद अवरुद्ध हो जाता है। यह केवल एक मुद्दा है यदि एक ही स्थिति चर का उपयोग एक से अधिक विधेय के लिए किया जा सकता है और आप उपयोग नहीं करते हैं pthread_cond_broadcast, जो वैसे भी एक दुर्लभ और नाजुक पैटर्न है।
डेविड श्वार्ट्ज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.