2012-11-16 9 views
16

सबसे पहले, मैं एक संक्षिप्त परिदृश्य समझाऊंगा;थ्रेड सुरक्षित कतार - एनक्यू/डेक्यू

कुछ डिवाइस ट्रिगर्स से सिग्नल के रूप में, अलार्म प्रकार की एक वस्तु को कतार में जोड़ा जाता है। एक अंतराल पर, कतार की जांच की जाती है, और कतार में प्रत्येक अलार्म के लिए, यह एक विधि को आग लगती है।

हालांकि, जिस समस्या में मैं दौड़ रहा हूं वह यह है कि, अगर किसी अलार्म को कतार में जोड़ा जाता है, जबकि इसे घुमाया जा रहा है, तो यह कहने में त्रुटि उत्पन्न होती है कि जब आप इसका उपयोग कर रहे थे तो कतार बदल गई है। मेरी कतार दिखाने के लिए यहां कुछ कोड दिया गया है, बस मान लें कि अलार्म लगातार इसमें डाला जा रहा है;

public class AlarmQueueManager 
{ 
    public ConcurrentQueue<Alarm> alarmQueue = new ConcurrentQueue<Alarm>(); 
    System.Timers.Timer timer; 

    public AlarmQueueManager() 
    { 
     timer = new System.Timers.Timer(1000); 
     timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); 
     timer.Enabled = true; 
    } 

    void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) 
    { 
     DeQueueAlarm(); 
    } 

    private void DeQueueAlarm() 
    { 
     try 
     { 
      foreach (Alarm alarm in alarmQueue) 
      { 
       SendAlarm(alarm); 
       alarmQueue.TryDequeue(); 
       //having some trouble here with TryDequeue.. 

      } 
     } 
     catch 
     { 
     } 
    } 

तो मेरा सवाल यह है कि, मैं इसे और कैसे बना सकता हूं ... थ्रेड सुरक्षित? ताकि मैं इन मुद्दों में भाग नहीं पाऊंगा। शायद कतार को दूसरी कतार में कॉपी करना, उस पर काम करना, फिर मूल कतार से निपटने वाले अलार्म को हटा देना?

संपादित करें: बस समवर्ती कतार के बारे में सूचित कर दिया गया है, इस बाहर की जाँच करेगा अब

+0

आपको पहले कतार से आइटम और SendAlarm सेकंड को पॉप करना चाहिए, साथ ही साथ एक सामान्य थ्रेड-सुरक्षित कतार कार्यान्वयन का उपयोग करना चाहिए। यदि आप किसी आइटम को संभाल नहीं सकते हैं तो इसे फिर से दबाएं। – cdleonard

उत्तर

18
private void DeQueueAlarm() 
{ 
    Alarm alarm; 
    while (alarmQueue.TryDequeue(out alarm)) 
     SendAlarm(alarm); 
} 

वैकल्पिक रूप से उपयोग नहीं कर सकते, तो आप इस्तेमाल कर सकते हैं:

private void DeQueueAlarm() 
{ 
    foreach (Alarm alarm in alarmQueue) 
     SendAlarm(alarm); 
} 

प्रति MSDN लेख ConcurrentQueue<T>.GetEnumerator पर:

गणन एक पल का प्रतिनिधित्व कतार की सामग्री का समय-समय पर स्नैपशॉट। यह GetEnumerator के बाद संग्रह के किसी भी अपडेट को प्रतिबिंबित नहीं करता है। गणनाकर्ता कतार में पढ़ने और लिखने के साथ समवर्ती रूप से उपयोग करने के लिए सुरक्षित है।

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

यदि आप प्रत्येक अलार्म को एक बार ठीक से संसाधित करना चाहते हैं, और बाद में इसे कतार से हटा दें, तो आपको पहले दृष्टिकोण का उपयोग करना चाहिए।

+0

तो कृपया संदर्भ के लिए, TryDequeue अलार्म को धक्का देता है, जिसे हम पहले घोषित अलार्म चर में बाहर निकालते हैं, और फिर इसका उपयोग करते हैं? –

+0

बिल्कुल। साथ ही, जब सूची खाली होती है, तो 'TryDequeue' 'false' लौटाता है, जिससे हमें' while' लूप से बाहर निकलने का कारण बनता है। – Douglas

+0

यह सुंदर निफ्टी है:) अब इसका परीक्षण करने जा रहा है। –

6

नेट पहले से ही एक धागा सुरक्षित कतार कार्यान्वयन है: ConcurrentQueue पर एक नजर है।

+0

मुझे "ट्रीडेक्यू()" के साथ कुछ परेशानी हो रही है। क्या आप शायद मेरी मदद कर सकते हैं? :) मैं अपने प्रश्न को एक ConcurrentQueue –

15

किसी भी कारण आप ConcurrentQueue<T>

+0

आह पर अपडेट करूंगा, मुझे इसके बारे में पता नहीं था! –

+0

मदद के लिए धन्यवाद – SHAHS

0

यह दृष्टिकोण एक बेहतर तरीका यह देखते हुए कि प्रत्येक थ्रेड वास्तव में केवल एक बार में एक अलार्म संसाधित कर रहा है, इस जगह की जाएगी:

 foreach (Alarm alarm in alarmQueue) 
     { 
      SendAlarm(alarm); 
      alarmQueue.TryDequeue(); 
      //having some trouble here with TryDequeue.. 
     } 
इस के साथ

:

 while (!alarmQueue.IsEmpty) 
     { 
      Alarm alarm; 
      if (!alarmQueue.TryDequeue(out alarm)) continue; 
      SendAlarm(alarm); 
     } 

वहाँ कोई कारण नहीं है किसी भी समय कतार का पूरा स्नैपशॉट प्राप्त करने के लिए, क्योंकि आप केवल प्रत्येक चक्र की शुरुआत में प्रक्रिया करने के लिए अगले व्यक्ति की वास्तव में परवाह करते हैं।

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