2013-02-20 35 views
6

हाल ही में मैं निम्न अपवाद में जब एक सामान्य शब्दकोशसमवर्ती शब्दकोश का उपयोग करना - थ्रेड सुरक्षित संग्रह संशोधन

एक InvalidOperationException आ गई है का उपयोग करते हुए चल रहा था। एक संग्रह संशोधित किया गया था

मुझे एहसास हुआ कि यह त्रुटि मुख्य रूप से स्थिर शब्दकोश पर थ्रेड सुरक्षा समस्याओं के कारण थी।

एक छोटी सी पृष्ठभूमि: मेरे पास वर्तमान में एक ऐसा एप्लिकेशन है जिसमें इस मुद्दे से संबंधित 3 अलग-अलग विधियां हैं।

  1. विधि ए foreach का उपयोग करके शब्दकोश के माध्यम से पुनरावृत्त करता है और एक मान देता है।
  2. विधि बी शब्दकोश में डेटा जोड़ता है।
  3. विधि सी शब्दकोश में कुंजी के मान को बदलता है।

कभी-कभी शब्दकोश के माध्यम से पुनरावृत्ति करते समय भी डेटा जोड़ा जा रहा है, जो इस मुद्दे का कारण है। मैं इस अपवाद को foreach में अपने कोड का हिस्सा प्राप्त करता हूं जहां मैं शब्दकोश की सामग्री पर पुन: प्रयास करता हूं। इस समस्या को हल करने के लिए, मैंने सामान्य शब्द को ConcurrentDictionary के साथ बदल दिया और यहां मैंने जो किया है उसके विवरण यहां दिए गए हैं।

उद्देश्य: मेरा मुख्य उद्देश्य पूरी तरह से अपवाद

विधि बी के लिए (जो शब्दकोश में नया कुंजी कहते हैं) मैं TryAdd

विधि सी के लिए साथ .Add प्रतिस्थापित दूर करने के लिए है (जो शब्दकोश के मूल्य को अद्यतन करता है) मैंने कोई बदलाव नहीं किया है। कोड का एक स्केच इस प्रकार है:

static public int ChangeContent(int para) 
    { 
     foreach (KeyValuePair<string, CustObject> pair in static_container) 
     { 
      if (pair.Value.propA != para) //Pending cancel 
      { 
       pair.Value.data_id = prim_id; //I am updating the content 
       return 0; 

      } 
     } 
    return -2; 
    } 

विधि के लिए एक - मैं बस शब्दकोश से अधिक पुनरावृत्ति कर रहा हूँ और इस जहां चल कोड बंद हो जाता है (डिबग मोड में) और दृश्य स्टूडियो मुझे इस है कि आपको सूचित करता है है, जहां त्रुटि occured.The कोड मैं उपयोग कर रहा हूँ निम्नलिखित

static public CustObject RetrieveOrderDetails(int para) 
    { 
      foreach (KeyValuePair<string, CustObject> pair in static_container) 
      {     
       if (pair.Value.cust_id.Equals(symbol)) 
       { 
        if (pair.Value.OrderStatus != para) 
        { 
         return pair.Value; //Found 
        } 
       } 
      } 
      return null; //Not found 
    } 

के समान है इन परिवर्तनों को अपवाद है कि मैं हो रही है को हल करने जा रहे हैं।

संपादित करें:

यह this page पर कहा गया है कि विधि GetEnumerator आप लेखन के साथ समानांतर में तत्वों के माध्यम से पार करने के लिए (हालांकि यह पुरानी हो सकती है) की अनुमति देता है। क्या वह foreach का उपयोग करने के समान नहीं है?

+0

फोएच वास्तव में ऐसा करता है - GetEnumerator/MoveNext/Current को कॉल करना। कृपया तीसरी विधि का कोड दिखाएं जो शब्दकोश की सामग्री को संशोधित करता है, जिस लाइन पर आपको अपवाद मिलता है? – Bond

+0

क्या मैं सही हूं कि आपने अभी तक एक नया दृष्टिकोण नहीं देखा है? – sll

+0

@ एसएलएल यहाँ एक जवाब था जिसने सुझाव दिया कि मैं '.ToList()' का उपयोग करता हूं और फिर परिणाम के माध्यम से पुन: प्रयास करता हूं। मुझे लगता है कि इसे हटा दिया गया है – MistyD

उत्तर

1

foreach() करने से पहले एक नया उदाहरण

var unboundContainer = static_container.ToList(); 
foreach (KeyValuePair<string, CustObject> pair in unboundContainer) 

के कंटेनर को कॉपी इसके अलावा, मैं Value संपत्ति को अद्यतन करने लगता है कि बाहर की कोशिश के बजाय TryUpdate() उपयोग करने के लिए अपने कोड refactor, सही धागा सुरक्षा दृष्टिकोण से नहीं है।

Dictionary<string, string> test = new Dictionary<string, string>(); 
int dictionaryLength = test.Count(); 

for (int i = 0; i < dictionaryLength; i++) 
{ 
    test[test.ElementAt(i).Key] = "Some new content"; 
} 

हालांकि थके हुए हो, कि यदि आप भी शब्दकोश में जोड़े जा रहे हैं, तो आप dictionaryLength को बढ़ा चाहिए:

3

तत्वों के संशोधन के लिए, एक ही विकल्प मैन्युअल रूप से पाश के लिए एक का उपयोग कर, जैसे शब्दकोश पुनरावृति करने के लिए है (या यदि आप तत्वों को स्थानांतरित करते हैं तो इसे कम करें) उचित रूप से।

आप जो कर रहे हैं उसके आधार पर, और यदि आदेश महत्वपूर्ण है, तो आप इसके बजाय सॉर्टेड डिक्शनरी का उपयोग करना चाह सकते हैं।

आप प्रत्येक पुनरावृत्ति पर test.Count() को याद करके स्पष्ट रूप से शब्दकोश लम्बाई को अपडेट करके इसे विस्तारित कर सकते हैं, और एक अतिरिक्त सूची का उपयोग भी कर सकते हैं जिसमें आप पहले ही संशोधित कर चुके हैं और इतने आगे और आगे यदि कोई खतरा है किसी को याद आ रही है, यह वास्तव में निर्भर करता है कि आप कुछ भी कर रहे हैं और आपकी ज़रूरतें क्या हैं।

आप आगे test.Keys.ToList() का उपयोग कुंजी की एक सूची प्राप्त कर सकते हैं, कि विकल्प के रूप में काम करेगा इस प्रकार है:

Dictionary<string, string> test = new Dictionary<string, string>(); 
List<string> keys = test.Keys.ToList(); 
foreach (string key in keys) 
{ 
    test[key] = "Some new content"; 
} 

IEnumerable<string> newKeys = test.Keys.ToList().Except(keys); 

if(newKeys.Count() > 0) 
    // Do it again or whatever. 

ध्यान दें कि मैं भी कैसे है कि क्या पता लगाने के लिए का एक उदाहरण दिखाया है कुंजी की प्रारंभिक सूची प्राप्त करने के बीच कोई भी नई कुंजी जोड़ दी गई थी, और पुनरावृत्ति को पूरा करने के लिए जैसे कि आप लूप को गोल कर सकते हैं और नई चाबियाँ संभाल सकते हैं।

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

+0

नियमित लूप के साथ, यह संभव है कि आप एक ही कुंजी को दो बार (या अधिक, हटाए गए/जोड़ों की संख्या के अनुसार) दोहराएं। निम्नलिखित परिदृश्य की कल्पना करें: आपके पास मूल्य 5 (10 का) है, जब अचानक एक तत्व जोड़ा जाता है। अब शब्दकोश तत्वों के क्रम की गारंटी नहीं देता है, इसलिए यह संभव है कि आइटम आपके तत्व से पहले जोड़ा गया हो। अब अगले पुनरावृत्ति में आप एक ही कुंजी/मूल्य जोड़ी का उपयोग कर रहे हैं! – Destrictor

+0

दरअसल, यह परिदृश्य है जिसमें मैं कहता हूं कि आपको शायद सॉर्टेड डिक्शनरी, या किसी प्रकार की ट्रैकिंग (यानी पहले से ही पुनरावृत्त तत्वों की एक सूची) की आवश्यकता होगी, लेकिन फिर से यह पूरी तरह से निर्भर करता है कि वह क्या हासिल करने की कोशिश कर रहा है - कुछ स्थितियों में आप इसके बारे में परवाह नहीं है और अपवाद के बिना संग्रह में आप जो भी कर सकते हैं उसे प्राप्त करना चाहते हैं। यह वास्तव में बहुत अच्छा परिदृश्य है कि "सर्वश्रेष्ठ" विकल्प वास्तव में क्या है। – Xefan