2013-06-03 9 views
22

मैं एक थ्रेड को रोकने के लिए एक सशर्त चर का उपयोग कर रहा हूं जब तक कि कोई अन्य धागा अपनी कार्य कतार (लंबी कहानी) को संसाधित नहीं कर लेता है। तो, एक धागे पर मैं ताला और इंतजार:प्रसंस्करण को पूरा करने के लिए धागे की प्रतीक्षा करने के लिए मैं बूस्ट कंडीशन चर का उपयोग कैसे करूं?

boost::mutex::scoped_lock lock(m_mutex); 
m_condition.wait(lock); 

अन्य धागा यह कार्य पूरा कर लिया है एक बार, यह प्रतीक्षा धागा संकेत है इस प्रकार है:

boost::mutex::scoped_lock lock(m_parent.m_mutex); 
m_parent.m_condition.notify_one(); 
समस्या मैं देख रहा हूँ

कि प्रतीक्षा है धागा इंतजार करना बंद नहीं करता है जब तक कि मैं इसके बाद दिए गए निर्देशों पर ब्रेकपॉइंट सेट नहीं करता (मैं xcode, fyi का उपयोग कर रहा हूं)। हाँ, यह अजीब लगता है। क्या किसी को पता है कि यह क्यों हो रहा है? क्या मैं कंडीशन वैरिएबल का गलत इस्तेमाल कर रहा हूं?

+0

कोड थोड़ा भ्रामक है ... पहले 'दूसरे' m_parent.m_mutex' रूप में एक ही उदाहरण m_mutex' है? –

उत्तर

42

हां, आप हालत चर का दुरुपयोग कर रहे हैं। "हालत चर" वास्तव में सिग्नलिंग तंत्र हैं। आपको एक शर्त का परीक्षण करने की भी आवश्यकता है। आपके मामले में क्या हो रहा है यह है कि notify_one() पर कॉल करने वाला थ्रेड वास्तव में wait() पर कॉल करने वाले थ्रेड से पहले पूरा हो जाता है। (या कम से कम, notify_one() कॉल wait() कॉल से पहले हो रहा है।) इसे "मिस्ड वेकअप" कहा जाता है।

समाधान वास्तव में एक चर जो हालत आप के बारे में परवाह शामिल है:

bool worker_is_done=false; 

boost::mutex::scoped_lock lock(m_mutex); 
while (!worker_is_done) m_condition.wait(lock); 

और

boost::mutex::scoped_lock lock(m_mutex); 
worker_is_done = true; 
m_condition.notify_one(); 

तो worker_is_done==true से पहले अन्य धागा भी तो इंतजार कर शुरू होता है तुम सिर्फ गिर जाएगा कभी भी wait() पर कॉल किए बिना लूप के माध्यम से।

यह पैटर्न इतना आम है कि मैं अब तक कहूंगा कि अगर आपके पास while लूप आपके condition_variable.wait() को लपेटने वाला नहीं है तो आपके पास हमेशा एक बग है। वास्तव में, जब सी ++ 11 बढ़ावा करने के लिए कुछ इसी तरह अपनाया :: condtion_variable वे प्रतीक्षा (एक नई तरह की) जोड़ा कि एक विधेय लैम्ब्डा अभिव्यक्ति लेता है (अनिवार्य रूप से यह आप के लिए while पाश करता है):

std::condition_variable cv; 
std::mutex m; 
bool worker_is_done=false; 


std::unique_lock<std::mutex> lk(m); 
cv.wait(lk, []{return worker_is_done;}); 
+0

'boost :: mutex :: scoped_lock लॉक (m_mutex) क्या है;' प्रतीक्षा थ्रेड में आवश्यक है? notify_one() तर्क नहीं लेता है। – ItsmeJulian

+0

'worker_is_done' पर परमाणु लेखन प्रदान करने के लिए यह है। विकल्प केवल 'बूल' के बजाय' परमाणु 'के रूप में घोषित करना है। –

+0

@ डेविडस्टोन क्या होगा यदि हम एक प्रोसेसर पर कोड चला रहे हैं जिसमें 1 बाइट असाइनमेंट परमाणु उदाहरण है। 86? हमें उस मामले में ताला की जरूरत नहीं होगी, है ना? – user3286661

2

मैंने एक उदाहरण लागू किया था जो चर्चा में आधारित बूस्ट हालत का उपयोग करने का तरीका बताता है।

#include <iostream> 

#include <boost/asio.hpp> 
#include <boost/thread/mutex.hpp> 
#include <boost/thread/thread.hpp> 

boost::mutex io_mutex; 
bool worker_is_done = false; 
boost::condition_variable condition; 

void workFunction() 
{ 
    std::cout << "Waiting a little..." << std::endl; 
    boost::this_thread::sleep(boost::posix_time::seconds(1)); 
    worker_is_done = true; 
    std::cout << "Notifying condition..." << std::endl; 
    condition.notify_one(); 
    std::cout << "Waiting a little more..." << std::endl; 
    boost::this_thread::sleep(boost::posix_time::seconds(1)); 
} 

int main() 
{ 
    boost::mutex::scoped_lock lock(io_mutex); 
    boost::thread workThread(&workFunction); 

    while (!worker_is_done) condition.wait(lock); 
    std::cout << "Condition notified." << std::endl; 
    workThread.join(); 
    std::cout << "Thread finished." << std::endl; 

    return 0; 
} 

Boost condition variable example

+3

क्या आप work_is_done को सत्य पर सेट करने से पहले कार्य में लॉक नहीं लेना चाहिए? –

+0

मुझे लगता है कि उसे चाहिए। –

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