मेरे पास एक विषय है जो ग्राहकों को Subscribe(Observer*)
और Unsubscribe(Observer*)
प्रदान करता है। विषय अपने स्वयं के धागे में चलता है (जिसमें से यह सब्सक्राइब किए गए पर्यवेक्षकों पर Notify()
पर कॉल करता है) और एक म्यूटेक्स पर्यवेक्षकों की अपनी आंतरिक सूची की सुरक्षा करता है।मैं multithreaded C++ में पर्यवेक्षक संबंध कैसे फाड़ सकता हूं?
मुझे क्लाइंट कोड चाहिए - जिसे मैं नियंत्रित नहीं करता - सदस्यता के बाद पर्यवेक्षक को सुरक्षित रूप से हटाने में सक्षम होने के लिए। यह कैसे हासिल किया जा सकता है?
- म्युटेक्स होल्डिंग - यहां तक कि एक पुनरावर्ती म्युटेक्स - जब मैं सूचित पर्यवेक्षकों क्योंकि गतिरोध जोखिम के एक विकल्प नहीं है।
- मैं सदस्यता रद्द करने में हटाने के लिए पर्यवेक्षक को चिह्नित कर सकता हूं और विषय धागे से हटा सकता हूं। फिर ग्राहक विशेष 'सुरक्षित करने के लिए सुरक्षित' अधिसूचना के लिए प्रतीक्षा कर सकते हैं। यह सुरक्षित दिखता है, लेकिन ग्राहकों के लिए अतिसंवेदनशील है।
संपादित
कुछ उदाहरण कोड इस प्रकार है। समस्या यह है कि जब सदस्यता 'यहां समस्या' टिप्पणी पर है, तो सदस्यता समाप्त होने से रोकने के लिए कैसे करें। फिर मैं एक हटाए गए ऑब्जेक्ट पर वापस कॉल कर सकता था। वैकल्पिक रूप से, अगर मैं प्रतिलिपि बनाने के बजाए म्यूटेक्स को पकड़ता हूं, तो मैं कुछ ग्राहकों को डेडलॉक कर सकता हूं।
#include <set>
#include <functional>
#include <boost/thread.hpp>
#include <boost/bind.hpp>
using namespace std;
using namespace boost;
class Observer
{
public:
void Notify() {}
};
class Subject
{
public:
Subject() : t(bind(&Subject::Run, this))
{
}
void Subscribe(Observer* o)
{
mutex::scoped_lock l(m);
observers.insert(o);
}
void Unsubscribe(Observer* o)
{
mutex::scoped_lock l(m);
observers.erase(o);
}
void Run()
{
for (;;)
{
WaitForSomethingInterestingToHappen();
set<Observer*> notifyList;
{
mutex::scoped_lock l(m);
notifyList = observers;
}
// Problem here
for_each(notifyList.begin(), notifyList.end(),
mem_fun(&Observer::Notify));
}
}
private:
set<Observer*> observers;
thread t;
mutex m;
};
संपादित
मैं क्योंकि गतिरोध जोखिम के म्युटेक्स दबाते हुए पर्यवेक्षकों को सूचित नहीं कर सकते। यह सबसे स्पष्ट तरीका हो सकता है - क्लाइंट कॉल नोटिफ़ाई के अंदर सदस्यता लें या सदस्यता छोड़ें - म्यूटेक्स रिकर्सिव बनाकर आसानी से उपचार किया जाता है। अधिक थकाऊ विभिन्न धागे पर अस्थायी डेडलॉक का खतरा है।
मैं एक बहुप्रचारित वातावरण में हूं, इसलिए थ्रेड के निष्पादन में किसी भी बिंदु पर, यह आमतौर पर ताले एल 1, एल 2, ... एलएन का अनुक्रम आयोजित करेगा। एक और धागा ताले K1, K2, ... Km होगा। एक उचित लिखित ग्राहक यह सुनिश्चित करेगा कि अलग-अलग धागे हमेशा एक ही क्रम में ताले हासिल करेंगे। लेकिन जब ग्राहक मेरे विषय के म्यूटेक्स से बातचीत करते हैं - इसे एक्स कहते हैं - यह रणनीति टूटी जाएगी: ऑर्डर करने के लिए कॉल करें/सदस्यता रद्द करें एल 1, एल 2, ... एलएन, एक्स। मेरे विषय धागे से अधिसूचित करने के लिए कॉल लॉक प्राप्त करें ऑर्डर एक्स, के 1, के 2, ... किमी। यदि ली या केजे में से कोई भी कॉल कॉल को कम कर सकता है, तो क्लाइंट को डिबग करने की थोड़ी संभावना के साथ, एक अस्थायी डेडलॉक पीड़ित है। चूंकि मैं क्लाइंट कोड को नियंत्रित नहीं करता, इसलिए मैं ऐसा नहीं कर सकता।
मुझे कुछ याद आ रही है। जब कोई विशिष्ट पर्यवेक्षक किसी अन्य पर्यवेक्षक की सदस्यता लेता है?विशिष्ट पर्यवेक्षक केवल स्वयं को सदस्यता छोड़ना चाहिए। अधिसूचना सूची में केवल एक ही पर्यवेक्षक हो सकता है, तो पहले से ही निकाला जाने वाला अधिसूचना कैसे पुरानी हो सकती है? – jmucchiello
ग्राहक किसी भी समय एक पर्यवेक्षक को सदस्यता छोड़ सकता है, न केवल अधिसूचना के अंदर। यह इस सामान्य मामले में है कि हमें विषय धागे के खिलाफ दौड़ मिलती है। – fizzer
@ फिज़ज़र: यह अस्पष्ट है कि आपने मेमोरी सुरक्षा कैसे कार्यान्वित की है। आप कैसे 'ऑब्जर्वर *' में 'पर्यवेक्षक' के सभी उदाहरण 'पर्यवेक्षक' के वैध उदाहरण की गारंटी देते हैं? –