2011-12-25 5 views
5

प्रकट नहीं होता है मैं इस विधि है:ताला बयान काम करने

public bool Remove(EntityKeyType key) 
{ 
    lock (syncroot) 
    { 
     //wait if we need to 
     waitForContextMRE.Wait(); 

     //if the item is not local, assume it is not remote. 
     if (!localCache.ContainsKey(key)) return false; 

     //build an expression tree 
     Expression<Func<EntityType, bool>> keyComparitorExpression = GenerateKeyComparitorExpression(key); 

     var itemToDelete = TableProperty.Single(keyComparitorExpression); 

     //delete from db 
     TableProperty.DeleteOnSubmit(itemToDelete); 
     DataContext.SubmitChanges(); 

     //get the removed item for OnCollectionChanged 
     EntityType itemToRemove = localCache[key]; 
     itemToRemove.PropertyChanged -= item_PropertyChanged; 

     //remove from the list 
     Debug.Assert(localCache.Remove(key)); 

     //call the notification 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, itemToRemove)); 
     return true; 
    } 
} 

मैं एक से अधिक थ्रेड से बोल रहा हूँ (एक ही उदाहरण बुला), लेकिन कोई अपवाद TableProperty.Single पर फेंक दिया जा रहा रखता है (अनुक्रम में शामिल है कोई तत्व नहीं)। कोड को डीबग करने पर मैंने देखा कि एक स्थिति बनाई जा रही है जहां डेटाबेस से आइटम को हटाया जा रहा है जब एक अलग धागे ने अपने अस्तित्व के लिए कैश की जांच की है। यह तब तक संभव नहीं होना चाहिए जब तक कि लॉक स्टेटमेंट के अंदर कई धागे न हों (सिंक्रूट ऑब्जेक्ट निश्चित रूप से धागे में एक ही उदाहरण है)।

असंभव? मेरे पास सबूत है: Impossible situation

लॉक स्टेटमेंट के अंदर तीन धागे हैं! क्या देता है?

नोट:

  1. MRE सेट किया गया है (नहीं अवरुद्ध)।
  2. यह ऐसी स्थिति नहीं है जहां अपवाद फेंक दिया जाता है, यह केवल लॉक सेक्शन के अंदर कई धागे दिखाता है। अद्यतन: मैंने छवि को अपवाद के इंटेलिट्रेस ईवेंट में बदल दिया। पुरानी छवि here
  3. सिंक्रूट ऑब्जेक्ट स्थिर नहीं है, क्योंकि मुझे केवल सिंक्रनाइज़ किए गए एक ही उदाहरण पर कॉल चाहिए।

    private object syncroot = new object(); 
    

    और कुछ अन्य घोषणाओं:

    private ManualResetEventSlim waitForContextMRE = new ManualResetEventSlim(true); 
    private DataContextType _dataContext; 
    private System.Data.Linq.Table<EntityType> _tableProperty; 
    //DataContextType and EntityType are generic type parameters 
    

    मैं syncroot स्थिर है क्योंकि मैं नहीं कर सकते हैं

अद्यतन

यह syncroot वस्तु की घोषणा है कक्षा के कई उदाहरण चल रहे हैं और यह महत्वपूर्ण है कि वे ब्लॉक न करें एक दूसरे के। लेकिन इससे कोई फर्क नहीं पड़ता - इसे स्थैतिक बनाना समस्या को ठीक नहीं करता है।

ManualResetEvent (waitForContextMRE) तुल्यकालन के लिए वहाँ नहीं है - यह एक निश्चित समय के लिए डेटाबेस कार्यों को ब्लॉक करने के बाद निश्चित संचालनों के प्रदर्शन कर रहे हैं वहाँ (अर्थात स्टार्टअप पर)। यह ज्यादातर समय सेट है। इसे लॉक ब्लॉक से बाहर लेना भी समस्या को ठीक नहीं करता है।

+1

ए: क्या हम देख सकते हैं कि आप 'सिंक्रोट' कहां शुरू कर रहे हैं, और बी: वस्तु-संदर्भ कितने समय तक लात मार रहा है? सी: क्या आप वाकई एक ही उदाहरण हैं? एक रोके गए राज्य से बताना मुश्किल है ... –

+1

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

+0

सिंक्रूट स्थिर बनाने में क्या नुकसान है? –

उत्तर

0

मैं थोड़ी देर के लिए इस समस्या को डीबग कर रहा हूं और, हालांकि मैंने इसे हल नहीं किया है, यह मुझे स्पष्ट है कि ताले काम कर रहे हैं।मुझे लगता है कि समस्या डेटाकॉन्टेक्स्ट (जो बहुप्रचारित परिस्थितियों में मुश्किल होने के लिए जाना जाता है) के साथ है।

+0

मुझे समस्या मिली है - 'Debug.Assert (localCache.Remove (key)) '- सी ++ की तरह ही जोर के अंदर की सामग्री रिलीज मोड में नहीं चलती है, जिससे डेटाबेस से आइटम्स को हटाया जा सकता है और कैश से नहीं । –

3

मेरे पास एकमात्र स्पष्टीकरण है कि waitForContextMRE.Wait(); इसे कॉल करने से थ्रेड सिंक्रूट को अनब्लॉक कर देता है! और इसलिए अन्य धागा ताला खंड में प्रवेश कर सकते हैं। WaitForContextMRE.Wait() को स्थानांतरित करने का प्रयास करें; लॉक से पहले (...)।

+0

मुझे नहीं लगता कि हम प्रतीक्षा निष्कर्ष निकालने के लिए waitForContextMRE के बारे में पर्याप्त देख सकते हैं; 'Monitor.Wait (सिंक्रूट) 'एकमात्र चीज है जो ताला जारी करेगी - और यह मेरे लिए स्पष्ट नहीं है कि यह वही है –

+0

यदि आप लॉक के अंदर हैं और मानते हैं कि कोई अन्य प्रक्रिया नहीं है तो कॉल प्रतीक्षा करें धागे का उपयोग कर? // प्रतीक्षा करें अगर हमें प्रतीक्षा करें ForContextMRE.Wait(); –

+0

कोशिश की - यह दुर्भाग्य से समस्या को ठीक नहीं करता है ... –

0

मैं ताला TableProperty या DataContext

+5

जिज्ञासा से बाहर ... के आधार पर? थ्रेडिंग मुद्दे इतने जटिल हैं कि ** किसी भी ** घुटने-झटके की प्रतिक्रिया से बचा जाना चाहिए, और किसी भी सिफारिश को प्रमाणित किया जाना चाहिए: और बी: तर्क –

+0

@Marc Gravell, धन्यवाद :-) –

+0

यह वास्तव में एक गंभीर था बिंदु मैं वहां बनाने की कोशिश कर रहा था ... –

3

मुझे लगता है कि आप विभिन्न वस्तुओं बुला रहे हैं सुझाव देते हैं। आपके स्क्रीनशॉट पर कोई संकेत नहीं है कि आप विभिन्न धागे से मूल्य ले रहे हैं। गैर स्थैतिक सिंक्रूट का उपयोग करना भी एक अच्छा विचार नहीं है क्योंकि परिणामस्वरूप आपके जैसे मामले हो सकते हैं। क्या आपके पास वास्तव में मजबूत कारण है कि यह स्थिर न हो?

+0

@Elastep मैं सहमत हूं कि एक ही वस्तु होने का सबूत काफी कम है - इसलिए अधिक जानकारी के लिए मेरा अनुरोध (अनुत्तरित) टिप्पणी के रूप में ... –

+0

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

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

  • कोई संबंधित समस्या नहीं^_^