2013-04-09 15 views
6

मुझे स्थिति चर के उपयोग से संबंधित मेरे कोड में डेडलॉक के साथ समस्या है। शुद्ध कोड प्रश्न की तुलना में यह एक डिजाइन सवाल है। सही डिजाइन को समझने के बाद मुझे वास्तव में कोड लिखने में कोई समस्या नहीं है। मेरे पास निम्नलिखित परिदृश्य है:कंडीशन वैरिएबल डेडलॉक

  1. थ्रेड ए एक शर्त चर पर प्रतीक्षा करता है।
  2. थ्रेड बी notify_all कॉल करता है, और थ्रेड ए जागता है।

यह निश्चित रूप से मैं क्या करना चाहता हूं, और यह तब होता है जब सब कुछ अपेक्षित काम करता है। लेकिन कभी-कभी, मुझे इसके बजाय निम्न परिदृश्य मिलता है:

  1. थ्रेड ए कंडीशन चर पर प्रतीक्षा करने से पहले कोड को सही तरीके से निष्पादित करता है।
  2. थ्रेड बी कॉल notify_all, सोच रहा है कि थ्रेड ए इंतजार कर रहा है।
  3. थ्रेड ए कंडीशन वैरिएबल पर इंतजार करना शुरू कर देता है, यह नहीं समझते कि थ्रेड बी ने पहले से ही इंतजार करना बंद कर दिया है। गतिरोध।

इसे हल करने का सबसे अच्छा तरीका क्या है? मैं यह देखने के लिए एक विश्वसनीय तरीका नहीं सोच सकता कि क्या थ्रेड ए वास्तव में प्रतीक्षा कर रहा है, यह जानने के लिए कि मुझे थ्रेड बी में notify_all कब कॉल करना चाहिए। क्या मुझे timed_lock का सहारा लेना है? मैं नफरत करता हूँ।

+0

आप किस लाइब्रेरी का उपयोग कर रहे हैं? क्या ओएस? –

+0

एक सेमफोर का प्रयोग करें। –

उत्तर

5

थ्रेड ए से पहले की अवधि के दौरान स्थिति परिवर्तनीय पर इंतजार कर रहा है, यह एक म्यूटेक्स धारण करना चाहिए। सबसे आसान समाधान यह सुनिश्चित करना है कि थ्रेड बी उसी समय mutex धारण कर रहा है जब वह notify_all को कॉल करता है। इस तरह तो कुछ:

std::mutex m; 
std::condition_variable cv; 
int the_condition = 0; 

Thread A: { 
    std::unique_lock<std::mutex> lock(m); 
    do something 
    while (the_condition == 0) { 
    cv.wait(lock); 
    } 
    now the_condition != 0 and thread A has the mutex 
    do something else 
} // releases the mutex; 

Thread B: { 
    std::unique_lock<std::mutex> lock(m); 
    do something that makes the_condition != 0 
    cv.notify_all(); 
} // releases the mutex 

यह गारंटी देता है कि धागा बी केवल notify_all करता है() या तो पहले धागा एक म्युटेक्स प्राप्त कर लेता है या जब थ्रेड एक शर्त चर पर इंतज़ार कर रहा है।

हालांकि, दूसरी कुंजी हालांकि, जबकि लूप को_condition सच होने का इंतजार है। एक बार ए में म्यूटेक्स हो जाने के बाद किसी भी अन्य थ्रेड को __condition को बदलने के लिए संभव नहीं होना चाहिए जब तक कि ए ने कंडिशन का परीक्षण नहीं किया है, इसे झूठा पाया है, और प्रतीक्षा करना शुरू कर दिया है (इस प्रकार म्यूटेक्स को छोड़ना)।

बिंदु यह है: आप वास्तव में इंतजार कर रहे हैं कि क्या आप वास्तव में इंतजार कर रहे हैं, क्योंकि शून्य-शून्य बनने के लिए, std :: condition_variable :: notify_all सिर्फ आपको बता रहा है कि थ्रेड बी थ्रेड थ्रेड को जागृत और रिस्टेस्ट करना चाहिए।

+3

+1 ध्यान दें कि 'std :: condition_variable :: wait' में एक अधिभार भी है जो एक अनुमान स्वीकार करता है। तो इसके बजाय 'the (the_condition == 0) cv.wait (ताला); 'आप इसके बजाय' cv.wait (लॉक, [&] {वापस the_condition! = 0;}) लिख सकते हैं;' –

+0

@AndrewDurward: यह मीठा है ! मुझे यह नहीं पता था। –

+1

आह हाँ, ज़ाहिर है। हास्यास्पद रूप से सरल। बस उसी म्यूटेक्स को लॉक करें कि कंडीशन वैरिएबल का उपयोग करता है, जब वास्तव में थ्रेड बी में सत्य को बदलते हैं। मैंने आपके कोड में अपना सुझाव लागू किया है और यह समस्या हल करता है। धन्यवाद! –

2

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

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