2012-01-05 5 views
5

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

क्या आपको कोई विचार है कि बहु-थ्रेडेड वातावरण में इन मुद्दों को कैसे नियंत्रित किया जाता है? साथ ही, क्या कोई सी ++ के साथ समांतर प्रोग्रामिंग पर कुछ किताबों की सिफारिश कर सकता है?

+0

यह इस एक सैद्धांतिक प्रश्न में एक थ्रेड पर्यवेक्षक पैटर्न लिखा? क्योंकि आपकी समस्या के लिए अन्य समाधान हो सकते हैं जिनमें तथाकथित 'पैटर्न' का उपयोग शामिल नहीं है। – INS

+0

विषय को "लॉक" होने की आवश्यकता नहीं है यदि यह जानकारी पर्यवेक्षकों के अद्यतन के दौरान बदलती नहीं है या परिवर्तन का कोई परिणाम नहीं है। एक उदाहरण के रूप में केवल पढ़ने के लिए फ़ाइल के बारे में सोचो। जहां तक ​​मैं सोच सकता हूं, यदि मैं आपके बिंदु को सही ढंग से समझ गया हूं तो बहु-थ्रेडिंग समस्या को हल नहीं करेगी।इसके अलावा अन्य धागे तब तक इंतजार कर सकते हैं जब तक कि विषय फिर से उपलब्ध न हो और समय-समय पर वापस न आएं और वहां "सूचना का नुकसान" नहीं होगा, लेकिन यह उस संदर्भ पर निर्भर करता है जो आपके द्वारा प्रदान की गई जानकारी की मात्रा से कल्पना करना मुश्किल है तुम्हारी समस्या। – Barracuda

उत्तर

6

producer-consumer queues या message queues के उपयोग पर विचार करें। आपके उदाहरण के लिए, आप दो तरह से एक कतार उपयोग कर सकते हैं: विषय को

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

  2. पर्यवेक्षकों को अधिसूचनाएं कतारबद्ध हैं। प्रत्येक पर्यवेक्षक के पास एक कतार है जहां विषय परिवर्तन-परिवर्तन अधिसूचनाएं पोस्ट की जाती हैं।

आप क्यूटी लाइब्रेरी का उपयोग कर रहे हैं, तो आप Qt::QueuedConnection कनेक्शन प्रकार के साथ संकेत & स्लॉट्स तंत्र का उपयोग कर सकते हैं। स्लॉट रिसीवर की घटना कतार के माध्यम से जाता है और रिसीवर के धागे में निष्पादित किया जाता है। इस तरह, प्रेषक ब्लॉक नहीं करता है जबकि रिसीवर अपने संबंधित स्लॉट निष्पादित करते हैं।

आपका प्रोग्राम Actor model (paradigm) के लिए एक अच्छा उम्मीदवार हो सकता है। यहाँ कुछ सी ++ पुस्तकालयों कि अभिनेता मॉडल को लागू कर रहे हैं:

आपका कार्यक्रम भी एक अच्छे उम्मीदवार हो सकता है Dataflow प्रतिमान के लिए। प्रस्तावित Boost Dataflow लाइब्रेरी देखें, जो threading का समर्थन करता है।


मैं सिफारिश करने के लिए एक किताब नहीं है, लेकिन हर्ब सुतर की series of Dr Dobbs articles सी पर ++ संगामिति की जाँच करें।

+0

बीटीडब्ल्यू: libcppa अभिनेताओं के लिए प्रकाशित/सब्सक्राइब आधारित समूह संचार का समर्थन करता है। विषय को आसानी से स्थानीय समूह के रूप में मॉडलिंग किया जा सकता है। किसी भी धागे/अभिनेता (प्रकाशक) समूह को भेज रहे हैं, समूह में शामिल होने से किसी भी संख्या में थ्रेड/अभिनेता (रिसीवर) प्राप्त कर सकते हैं। – neverlord

1

मैं जावा

 

    import java.lang.reflect.Method; 
    import java.util.List; 
    import java.util.Map; 
    import java.util.Map.Entry; 

    /** 
    * An observer pattern that allows listeners to register(), unregister() in 
    * multiple threads and also notify listeners in another thread. 
    * 
    * A HashMap keeps track of the listeners and their status (active, obsolete). 
    * When a listener unregister, its entry is marked as obsolete in this map. 
    * 
    * During firing of an event, the observer notifies all the listeners that are 
    * active, the active status will be stored in a Boolean that's synchronized so 
    * rare race conditions like calling notify on an active listener that has just 
    * turned obsolete will not happen. 
    * 
    * 
    */ 
    public class MultithreadedObserverPattern { 

     interface Handler { 
      void handleEvent(T listener); 
     } 

     class BooleanHolder { 
      boolean val; 

      BooleanHolder(boolean v) { 
       val = v; 
      } 

      void set(boolean v) { 
       val = v; 
      } 

      boolean get() { 
       return val; 
      } 
     } 

     Map listeners = new HashMap(); 

     public void register(AbstractListener l) { 
      synchronized (listeners) { 
       listeners.put(l, new BooleanHolder(true)); 
      } 
     } 

     public void unregister(AbstractListener l) { 
      synchronized (listeners) { 
       BooleanHolder status = listeners.get(l); 
       if (status != null) { 
        // notify call also syncing on status 
        synchronized (status) { 
         status.set(false); 
        } 
       } 
       // set to false 
      } 
     } 

     public void notifyAll(Handler handler) { 
      // here we do not synchroznie on listeners to avoid tricky lock situations 
      // make a copy of the map 
      List> activeListeners = new ArrayList>(); 
      List inactiveListeners = new ArrayList(); 

      synchronized (listeners) { 
       for (Entry entry : listeners.entrySet()) { 
        if (entry.getValue().get()) { 
         activeListeners.add(entry); 
        } else { 
         inactiveListeners.add(entry.getKey()); 
        } 
       } 
      } 
      // call the method on active listener 
      // 
      for (Entry e : activeListeners) { 
       BooleanHolder status = e.getValue(); 
       // remove those listeners that are no longer active 
       synchronized (status) { 
        if (status.get()) { 
          handler.handleEvent(e.getKey()); 
        } 
       } 
      } 

      synchronized (listeners) { 
       // remove inactive listeners 
       for (AbstractListener l : inactiveListeners) { 
        listeners.remove(l); 
       } 
      } 
     } 
    }