2016-05-12 14 views
5

मुझे यकीन नहीं है कि मुझे वास्तव में समझ में आता है कि std::condition_variable को पैरामीटर के रूप में अतिरिक्त std::mutex क्यों चाहिए? क्या यह अपने आप से लॉक नहीं होना चाहिए?std :: condition_variable इसकी आवश्यकता क्यों है std :: mutex

#include <iostream> 
#include <condition_variable> 
#include <thread> 
#include <chrono> 

std::condition_variable cv; 
std::mutex cv_m; 
int i = 0; 
bool done = false; 

void waits() 
{ 
    std::unique_lock<std::mutex> lk(cv_m); 
    std::cout << "Waiting... \n"; 
    cv.wait(lk, []{return i == 1;}); 
    std::cout << "...finished waiting. i == 1\n"; 
    done = true; 
} 

void signals() 
{ 
    std::this_thread::sleep_for(std::chrono::seconds(1)); 
    std::cout << "Notifying falsely...\n"; 
    cv.notify_one(); // waiting thread is notified with i == 0. 
        // cv.wait wakes up, checks i, and goes back to waiting 

    std::unique_lock<std::mutex> lk(cv_m); 
    i = 1; 
    while (!done) 
    { 
     std::cout << "Notifying true change...\n"; 
     lk.unlock(); 
     cv.notify_one(); // waiting thread is notified with i == 1, cv.wait returns 
     std::this_thread::sleep_for(std::chrono::seconds(1)); 
     lk.lock(); 
    } 
} 

int main() 
{ 
    std::thread t1(waits), t2(signals); 
    t1.join(); 
    t2.join(); 
} 

माध्यमिक, उदाहरण में वे म्युटेक्स अनलॉक पहले (signals विधि)। वे ऐसा क्यों कर रहे हैं? क्या उन्हें पहले लॉक नहीं करना चाहिए और फिर अधिसूचना के बाद अनलॉक करना चाहिए?

उत्तर

2

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

एक शर्त चर एक ट्रिगर के लिए इंतजार कर रहा है ताकि वह इसकी स्थिति की जांच कर सके। इसकी स्थिति की जांच करने के लिए, इसे एक प्रश्न पूछने की जरूरत है।

यदि आप प्रतीक्षा करने से पहले लॉक नहीं करते हैं, तो यह संभव है कि आप सवाल पूछें और शर्त प्राप्त करें, और आपको बताया जाता है कि स्थिति गलत है। यह एक झूठ बन जाता है क्योंकि ट्रिगर होता है और स्थिति सच हो जाती है। लेकिन आप इसे नहीं जानते हैं, क्योंकि इस प्रभावी ढंग से सिंगल-थ्रेडेड बनाने के लिए कोई म्यूटक्स नहीं है।

इसके बजाय, आप ट्रिगर के लिए कंडीशन वैरिएबल पर प्रतीक्षा करें जो कभी भी आग नहीं लगेगा, क्योंकि यह पहले से ही किया गया है। यह deadlocks।

+1

ठीक है, उस स्पष्टीकरण के लिए धन्यवाद। लेकिन क्या मैं पूछ सकता हूं कि इसे सीधे 'std :: condition_variable' के कार्यान्वयन में क्यों नहीं रखा गया है? – Pascal

+0

यह है। यही कारण है कि कंडीशन वैरिएबल का प्रतीक्षा फ़ंक्शन लॉक को पैरामीटर के रूप में ले जाता है! –

4

म्यूटेक्स भविष्यवाणी की रक्षा करता है, यानी, जिस चीज की आप प्रतीक्षा कर रहे हैं। चूंकि आप जिस चीज की प्रतीक्षा कर रहे हैं, वह है, जरूरी है कि धागे के बीच साझा किया जाए, इसे किसी भी तरह से संरक्षित किया जाना चाहिए।

ऊपर दिए गए आपके उदाहरण में, i == 1 अनुमान है। म्यूटेक्स i की सुरक्षा करता है।

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

लेकिन धागा mutex को जारी नहीं कर सकता है और फिर प्रतीक्षा कर सकता है। क्या होगा यदि म्यूटेक्स जारी होने के बाद राज्य बदल गया लेकिन धागा इंतजार करने में कामयाब रहे? तो आपको एक परमाणु "अनलॉक और प्रतीक्षा" ऑपरेशन की आवश्यकता है। यह विशेष रूप से क्या स्थिति चर प्रदान करता है।

कोई म्यूटेक्स के साथ, वे क्या अनलॉक करेंगे?

लॉक जारी करने से पहले या बाद में हालत चर को सिग्नल करने का विकल्प दोनों पक्षों के फायदे के साथ एक जटिल है।

+1

अच्छा स्पष्टीकरण! –

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