2012-02-27 13 views
5

मैं न्यूनतम कार्यों के साथ एक concurrent_blocking_queue को लागू कर रहा हूँ:उत्पादक होने पर उपभोक्ता को सूचित करने के सुरुचिपूर्ण तरीके?

//a thin wrapper over std::queue 
template<typename T> 
class concurrent_blocking_queue 
{ 
    std::queue<T> m_internal_queue; 
    //... 
public: 
    void add(T const & item); 
    T& remove(); 
    bool empty(); 
}; 

मैं producer-consumer problem के लिए इसका उपयोग करना चाहते हैं (मुझे लगता है, यह वह जगह है जहाँ एक का उपयोग करता इस तरह के डेटा संरचनाओं?)। लेकिन मैं एक समस्या पर फंस गया हूं जो है:

उत्पादक होने पर उपभोक्ता को सुंदरता से कैसे सूचित किया जाए? उत्पादक कतार को कब सूचित करेगा जब यह किया जाता है? एक निर्दिष्ट सदस्य फ़ंक्शन को कॉल करके, done() कहें? कतार से अपवाद फेंक रहा है (यानी remove फ़ंक्शन से) एक अच्छा विचार है?

मैं कई उदाहरणों में आया, लेकिन सभी में अनंत लूप है जैसे निर्माता हमेशा के लिए वस्तुओं का उत्पादन करेगा। किसी ने भी रोकथाम की स्थिति के मुद्दे पर चर्चा नहीं की, यहां तक ​​कि wiki article भी नहीं।

+0

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

+0

@ स्टेवजेसॉप: हां। मैं इसे सामान्य बनाना चाहता हूं। विशेष मूल्य का विचार अच्छा प्रतीत नहीं होता है। कुछ विशेष मूल्य कुछ 'टी' के लिए मान्य मान हो सकता है, या मेरी भावना कहती है कि यह अच्छा नहीं है। – Nawaz

+0

मैं प्रस्ताव दे रहा हूं कि निर्माता विशेष मूल्य का चयन और दस्तावेज करता है। यदि वे एक ऐसे मान का उपयोग करते हैं जिसका एक और अर्थ भी है, तो वे शायद बेवकूफ या कुछ हैं। –

उत्तर

1

मेरे कतार आमतौर पर इस्तेमाल किया है संकेत ( इंटरफ़ेस में एक std::auto_ptr साथ, स्पष्ट रूप से संकेत मिलता है कि इस नहीं रह गया है सूचक का उपयोग कर सकते हैं); अधिकांश भाग के लिए, कतारबद्ध वस्तुएं पॉलिमॉर्फिक थीं, इसलिए गतिशील आवंटन और संदर्भ अर्थशास्त्र की आवश्यकता थी। अन्यथा, “ फ़ाइल ” कतार में ध्वज जोड़ने के लिए बहुत मुश्किल नहीं होना चाहिए। आपको निर्माता पक्ष (close?) पर सेट करने के लिए एक विशेष फ़ंक्शन की आवश्यकता होगी (इसे उसी लॉकिंग प्राइमेटिव्स का उपयोग करके जब आप कतार में लिखते हैं), और फ़ंक्शन को हटाने में लूप को किसी चीज़ के लिए प्रतीक्षा करनी होगी वहां रहें, या कतार बंद हो। बेशक, आपको Fallible मान वापस करने की आवश्यकता होगी, ताकि पाठक यह जान सके कि पढ़ना सफल हुआ या नहीं। साथ ही, मत भूलें कि इस मामले में, आपको यह सुनिश्चित करने के लिए notify_all की आवश्यकता है कि सभी स्थिति पर प्रतीक्षा की जाने वाली प्रक्रियाएं जागृत हों।

बीटीडब्लू: मैं बिल्कुल नहीं देखता कि आपका इंटरफ़ेस कैसे कार्यान्वित किया जा सकता है। T&remove द्वारा लौटाया गया है। असल में, remove कुछ की तरह हो गया है: यहां तक ​​कि myIsDone शर्त के बिना

Fallible<T> 
MessageQueue<T>::receive() 
{ 
    ScopedLock l(myMutex); 
    while (myQueue.empty() && ! myIsDone) 
     myCondition.wait(myMutex); 
    Fallible<T> results; 
    if (!myQueue.empty()) { 
     results.validate(myQueue.top()); 
     myQueue.pop(); 
    } 
    return results; 
} 

, आप कतार से निकालने से पहले एक स्थानीय चर में मूल्य को पढ़ने के लिए है, और आप एक संदर्भ वापस नहीं लौट सकते एक स्थानीय चर के लिए।

बाकी के लिए:

void 
MessageQueue<T>::send(T const& newValue) 
{ 
    ScopedLock l(myMutex); 
    myQueue.push(newValue); 
    myCondition.notify_all(); 
} 

void 
MessageQueue<T>::close() 
{ 
    ScopedLock l(myMutex); 
    myIsDone = true; 
    myCondition.notify_all(); 
} 
+0

आपके 'प्राप्त() 'कार्यान्वयन में,' while' लूप हमेशा के लिए अवरुद्ध नहीं है, क्योंकि म्यूटेक्स को' प्रेषण '(या' बंद ') में कभी भी अधिग्रहित नहीं किया जाएगा क्योंकि यह पहले से ही' प्राप्त 'द्वारा अधिग्रहित किया गया है जो' * सोने से पहले * इसे छोड़ने के लिए? – Nawaz

+0

@ नवाज यह 'myCond.wait()' कहता है, जो इसे अनब्लॉक करता है। वास्तव में, कोड में एक संभावित त्रुटि, या कम से कम कुछ भ्रामक है, क्योंकि एक शर्त पर सभी 'प्रतीक्षा()' फ़ंक्शंस जो मुझे पता है कि म्यूटेक्स को भी तर्क के रूप में लेना है।पूरी बात यह है कि जब तक आप म्यूटेक्स जारी नहीं करते हैं और जिस क्षण आप प्रतीक्षा करना चाहते हैं, उस बीच मध्यस्थता की किसी भी अन्य प्रक्रिया से बचने के लिए आपको वास्तव में इंतजार कर रहे हैं, तब तक आपको म्यूटेक्स को पकड़ना होगा। 'myCond.wait() 'परमाणु रूप से म्यूटेक्स को छोड़ देना चाहिए और आपको प्रतीक्षा करना चाहिए। मैं इसे प्रतिबिंबित करने के लिए प्रतिक्रिया संपादित करूंगा। –

+0

मुझे तर्क नहीं मिला कि आपने कहा कि 'निकालें' फ़ंक्शन को 'T &' के बजाय 'Fallible ' वापस करना चाहिए? 'फॉलिबल' क्या है? – Nawaz

5

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

+0

+1, हमेशा एक अच्छा दृष्टिकोण। – Tudor

+0

"* ** प्रकार का एक उत्पाद **" किया "*"? इसका क्या मतलब है? यदि आपका मतलब एक विशेष मूल्य है, तो वह विशेष मान कुछ 'टी' के लिए मान्य मान हो सकता है। कहें, अगर 'टी = int', 'किया गया' इंगित करने के लिए मैं किस विशेष मूल्य का चयन करूंगा? आप कुछ मूल्य 'एन' कहेंगे, तो हो सकता है कि 'एन' निर्माता द्वारा उत्पादित मूल्यों में से एक है, वैसे भी? – Nawaz

+0

कोई प्रॉक्सी प्रकार एम लागू कर सकता है जो एक विधि bool try_get (T &) लागू करता है और यदि यह 'डेटा का अंत' अधिसूचना –

2

यह सच है कि एक विशेष "हम कर चुके हैं" संदेश को स्वीकार करना आम है; हालांकि मुझे लगता है कि आउट ऑफ़ बैंड संकेतक के लिए ओपी की मूल इच्छा उचित है। जटिलता को देखो, लोग इन-बैंड समापन संदेश सेट अप करने पर विचार कर रहे हैं! प्रॉक्सी प्रकार, templating; सुखद दुख। मैं कहूंगा कि done() विधि सरल और आसान है, और यह सामान्य मामला बनाता है (हम अभी तक नहीं किए गए हैं) तेज़ और क्लीनर।

मैं बच्चों_फॉक्स से सहमत हूं कि कतारबद्ध होने पर एक try_remove त्रुटि कोड लौटाता है, लेकिन यह स्टाइलिस्ट और वाईएमएमवी है।

संपादित करें: एक कतार है कि कैसे कई निर्माताओं एक बहु-उत्पादकों स्थिति में शेष रहे हैं का ट्रैक रखता है और किया अपवाद iff सभी उत्पादकों तौलिया में फेंक दिया है को जन्म देती है लागू करने के लिए बोनस अंक ;-) नहीं क्या करने जा इन-बैंड संदेशों के साथ !

+0

मैं असहमत हूं। बस शुरू करने के लिए, कतार कैसे ट्रैक कर सकती है कि कितने उत्पादक शेष हैं - कतार को यह नहीं पता कि सिस्टम में कितने उत्पादक हैं। –

+0

@ मार्टिनजम्स: कतार को इस तरह कार्यान्वित किया जा सकता है ताकि यह उत्पादकों का ट्रैक रख सके? कुछ 'queue.register_producer (यह)' और फिर 'queue.unregister_producer (यह)' जैसी कुछ है? – Nawaz

+0

@ नवाज - हां, यह संभव है, लेकिन लचीलापन और प्रभाव encapsulation को सीमित करता है - इसका मतलब है कि निर्माता को कतार वर्ग तक सीधे पहुंच होनी चाहिए, जो अक्सर वांछित नहीं है और/या व्यवस्था करने के लिए जटिल है। क्या होता है यदि कोई निर्माता लॉग इन नहीं करता है, या एक से अधिक बार लॉग करता है? अगर मैं कतार के साथ पंजीकरण करता हूं और बाद में जारी रखना नहीं चाहता हूं, तो क्या मुझे पंजीकरण रद्द करना होगा और यदि ऐसा है, तो क्या मुझे यह सुनिश्चित करना होगा कि मेरी सभी उत्कृष्ट वस्तुओं को संसाधित किया जाए? –

1

'रोकना' अक्सर चर्चा नहीं की जाती है क्योंकि यह अक्सर कभी नहीं किया जाता है। उन मामलों में जहां इसकी आवश्यकता होती है, यह अक्सर उच्च स्तर के पी-सी प्रोटोकॉल का उपयोग करके जहर-गोली को जुटाने के लिए जितना आसान और अधिक लचीला होता है क्योंकि यह कतार में अतिरिक्त कार्यक्षमता का निर्माण होता है।

यदि आप वास्तव में ऐसा करना चाहते हैं, तो आप वास्तव में एक ध्वज सेट कर सकते हैं जो प्रत्येक उपभोक्ता को अपवाद उठाने का कारण बनता है, या तो 'तुरंत' या जब भी यह कतार में वापस आता है, लेकिन समस्याएं होती हैं। क्या आपको सिंक्रोनस होने के लिए 'पूर्ण' विधि की आवश्यकता है, यानी। क्या आप चाहते हैं कि सभी उपभोक्ता 'किए गए' रिटर्न, या असीमित, यानी समय से चले गए हों। आखिरी उपभोक्ता धागा एक घटना पैरामीटर कहता है जब अन्य सभी उपभोक्ता चले जाते हैं?

आप उन उपभोक्ताओं के लिए व्यवस्था कैसे कर रहे हैं जो वर्तमान में जागने की प्रतीक्षा कर रहे हैं? कितने इंतजार कर रहे हैं और कितने व्यस्त हैं, लेकिन जब वे अपना काम करते हैं तो कतार में वापस आ जाएंगे? क्या होगा यदि एक या अधिक उपभोक्ता अवरुद्ध कॉल पर फंस गए हों, (शायद उन्हें अनब्लॉक किया जा सकता है, लेकिन इसके लिए किसी अन्य थ्रेड से कॉल की आवश्यकता होती है - आप इसे कैसे करने जा रहे हैं)?

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

ओह हाँ - सुरक्षित होने के लिए, आपको निर्माता धागे की व्यवस्था करनी चाहिए जो अपवाद बढ़ाने के लिए 'शट डाउन' स्थिति में कतार में ऑब्जेक्ट्स के साथ बदलना चाहिए।

मैं इन प्रश्नों को उठाता हूं क्योंकि मैंने बहुत समय पहले यह सब किया है। आखिरकार, यह सब काम किया- आईएसएच। जिन वस्तुओं को कतारबद्ध किया गया था, उन्हें 'क्वीडइटम' अपनी विरासत श्रृंखला में डाला गया था, (ताकि नौकरी रद्दीकरण विधि को कतार में उजागर किया जा सके), और कतार को वस्तुओं की थ्रेड-सुरक्षित सूची रखना था धागे द्वारा पॉप-ऑफ बंद लेकिन अभी तक संसाधित नहीं किया गया है।

थोड़ी देर के बाद, मैंने एक विशेष पी-सी कतार के पक्ष में कक्षा का उपयोग बंद कर दिया, जिसमें कोई विशेष शट डाउन तंत्र नहीं था।

+0

उपभोक्ताओं को जागने के बारे में बिंदु जो पहले से ही इंतजार कर रहे हैं वह एक अच्छा है; सरलता सेमेफोर (मुझे लगता है) बढ़ाना होगा जो कतार की रक्षा कर रहा है। ओपी एकल उपभोक्ता सिंगल-निर्माता के बारे में था, इसलिए यह पर्याप्त है। आपके द्वारा चर्चा की जाने वाली अधिकांश जटिलताओं को() सिंक्रोनस करने के संबंध में है, हालांकि, यदि यह आवश्यक नहीं है तो कक्षा लिखने में बुरा नहीं है। – zmccord

+0

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

+0

@zmccord - ओपी पोस्ट थोड़ा अस्पष्ट था। 'सिंगल-कंज्यूमर सिंगल-प्रोड्यूसर' - हाँ, ठीक है, लेकिन ऐसी कतार बहुत उपयोगी/लचीली नहीं हैं और कुछ हद तक असुरक्षित हैं - इससे कोई फ़र्क नहीं पड़ता कि आपने कितना दस्तावेज़ डाला है, कुछ डेवलपर्स आखिरकार किसी अन्य थ्रेड से संदेश पर फेंक देंगे। 'असली' पी-सी कतार बिना शर्त सुरक्षित हैं। यदि 'किया गया' को तुल्यकालिक होने की आवश्यकता नहीं है और कोई समापन अधिसूचना की आवश्यकता नहीं है, तो हां, बस एक शून्य/शून्य/जो भी अवैध वस्तु पर फेंक दें और प्रत्येक उपभोक्ता थ्रेड इसे बंद कर दें, इसे पहचानें, इसे वापस धक्का दें और फिर मर जा। –

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

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