2016-04-08 20 views
9

हम विजुअल स्टूडियो एक्सटेंशन में XML दस्तावेज़ को संशोधित करने के लिए Microsoft.VisualStudio.XmlEditor नेमस्पेस (https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.xmleditor.aspx) में कक्षाओं का उपयोग कर रहे हैं।VSIX - XmlEditingScope.Complete पर डेडलॉक()

किसी कारण से XmlEditingScope.Complete() विधि को कॉल करने के बाद एक डेडलॉक होता है।

WindowsBase.dll!System.Windows.Threading.DispatcherSynchronizationContext.Wait(System.IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout) 
mscorlib.dll!System.Threading.SynchronizationContext.InvokeWaitMethodHelper(System.Threading.SynchronizationContext syncContext, System.IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout)  
[Native to Managed Transition] 
[Managed to Native Transition] 
mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) 
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) 
Microsoft.VisualStudio.Package.LanguageService.14.0.dll!Microsoft.VisualStudio.Package.LanguageService.ParseWaitHandle.WaitOne(int millisecondsTimeout, bool exitContext)  
Microsoft.XmlEditor.dll!Microsoft.XmlEditor.XmlLanguageService.WaitForParse(System.IAsyncResult result, Microsoft.XmlEditor.StatusBarIndicator indicator)  
Microsoft.XmlEditor.dll!Microsoft.XmlEditor.XmlLanguageService.WaitForParse()  
Microsoft.XmlEditor.dll!Microsoft.XmlEditor.XmlParserLock.XmlParserLock(Microsoft.XmlEditor.XmlLanguageService service) 
Microsoft.XmlEditor.dll!Microsoft.XmlEditor.Transaction.PushToEditorTreeAndBuffer() 
Microsoft.XmlEditor.dll!Microsoft.XmlEditor.Transaction.Complete() 
XmlEditingScope.Complete() Line 64 

और विजुअल स्टूडियो: विजुअल स्टूडियो के स्थिति बार में, हम संदेश "पार्स को पूरा करने के लिए प्रतीक्षा कर रहा ..."

इस गतिरोध यूआई धागे की स्टैक ट्रेस है देखना पार्स धागा:

mscorlib.dll!System.Threading.WaitHandle.InternalWaitOne(System.Runtime.InteropServices.SafeHandle waitableSafeHandle, long millisecondsTimeout, bool hasThreadAffinity, bool exitContext) + 0x21 bytes 
mscorlib.dll!System.Threading.WaitHandle.WaitOne(int millisecondsTimeout, bool exitContext) + 0x28 bytes  
Microsoft.XmlEditor.dll!Microsoft.XmlEditor.LockManager.Lock(object resource, Microsoft.XmlEditor.LockMode mode, Microsoft.XmlEditor.Transaction txId) + 0x14c bytes  
Microsoft.XmlEditor.dll!Microsoft.XmlEditor.TransactionManager.BeginParseSourceTransaction(Microsoft.XmlEditor.XmlSource src, Microsoft.XmlEditor.Transaction parent) + 0x9f bytes 
Microsoft.XmlEditor.dll!Microsoft.XmlEditor.XmlLanguageService.ParseSource(Microsoft.VisualStudio.Package.ParseRequest req) + 0x17d bytes  
Microsoft.VisualStudio.Package.LanguageService.14.0.dll!Microsoft.VisualStudio.Package.LanguageService.ParseRequest(Microsoft.VisualStudio.Package.ParseRequest req) + 0x75 bytes  
Microsoft.VisualStudio.Package.LanguageService.14.0.dll!Microsoft.VisualStudio.Package.LanguageService.ParseThread() + 0x140 bytes 
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart_Context(object state) + 0x70 bytes  
mscorlib.dll!System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0xa7 bytes 
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state, bool preserveSyncCtx) + 0x16 bytes 
mscorlib.dll!System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext executionContext, System.Threading.ContextCallback callback, object state) + 0x41 bytes  
mscorlib.dll!System.Threading.ThreadHelper.ThreadStart() + 0x44 bytes  
[Native to Managed Transition] 

यह यहाँ सभी प्रासंगिक कोड को दिखाने के लिए आसान नहीं है, लेकिन मूल रूप से यह सिर्फ निम्न कोड है कि एक WPF डेटा ग्रिड नियंत्रण में बदलाव के बाद क्रियान्वित किया जाता है (IEditableObject.EndEdit व्यूमोडेल में):

using (var s = store.BeginEditingScope("Test", null)) 
{ 
     apply changes in xmlModel.Document... 

     s.Complete(); 
} 

इस डेडलॉक को होने से रोकने के लिए मैं क्या कर सकता हूं। क्या परिवर्तनों को लागू करने से पहले मुझे कुछ लॉक करने की ज़रूरत है? मैं और क्या गलत कर रहा हूँ?

उत्तर

0

यह एक टिप्पणी है लेकिन एक टिप्पणी क्षेत्र में फिट नहीं हुआ। आपके मामले में ऐसा क्यों होता है या आपके द्वारा प्रदान की गई जानकारी के साथ इसे ठीक करने का एक तरीका प्रदान करने के लिए सही कारण बता देना मुश्किल है (अधिक सहायता प्रदान करने के लिए हमें न्यूनतम उदाहरण की आवश्यकता है जिसे हम केवल चला सकते हैं और समस्या देख सकते हैं)। हालांकि, स्टैकट्रैस दिखाते हैं कि यह नियमित यूआई डेडलॉक होता है जो अक्सर "यूआई थ्रेडेड" प्रकृति की वजह से लगभग सभी यूआई ढांचे में होता है (यूआई तत्वों के साथ सभी \ अधिकांश क्रियाएं एकल धागे पर होती हैं)। थ्रेड ए (इस मामले में विजुअल स्टूडियो पार्स थ्रेड) पृष्ठभूमि थ्रेड से यूआई थ्रेड कतार में एक कार्य पोस्ट करता है और इसे पूरा करने के लिए इंतजार कर रहा है (उदाहरण के लिए WPF डिस्पैचर। इन्वोक कॉल जो वास्तव में करता है)। यह आवश्यक नहीं है कि पूरे कार्य को डेडलॉक के लिए यूआई थ्रेड पर निष्पादित किया जाए, केवल इसका एक हिस्सा (उदाहरण के लिए - यूआई नियंत्रण से वास्तविक एक्सएमएल प्राप्त करें) पर्याप्त है। फिर आप UI थ्रेड पर ही ऐसा ही कर रहे हैं। यूआई थ्रेड में कुछ प्रतीक्षा हैंडल पर प्रतीक्षा करें (यूआई थ्रेड पर लॉक स्टेटमेंट का उपयोग उसी श्रेणी में आता है)। यह बेहद खतरनाक है और इस मामले में आपके (संभवतः) डेडलॉक्स की ओर जाता है।

मैं इस छोटा सा उदाहरण (WPF) के साथ मेरी बात को वर्णन होगा:

public partial class MainWindow : Window { 
    private DummyXmlParser _test = new DummyXmlParser(); 
    public MainWindow() { 
     InitializeComponent(); 
     new Thread(() => { 
      _test.StartParseInBackground(); 
      _test.WaitHandle.WaitOne(); 
     }) { 
      IsBackground = true 
     }.Start(); 

     _test.StartParseInBackground(); 
     // don't do this, will deadlock 
     _test.WaitHandle.WaitOne(); 
    } 
} 

public class DummyXmlParser { 
    public DummyXmlParser() { 
     WaitHandle = new ManualResetEvent(false); 
    } 

    public void StartParseInBackground() { 
     Task.Run(() => { 
      Thread.Sleep(1000); 
      // this gets dispatched to UI thread, but UI thread is blocked by waiting on WaitHandle - deadlock 
      Application.Current.Dispatcher.Invoke(() => 
      { 
       Application.Current.MainWindow.Title = "Running at UI"; 
      }); 
      WaitHandle.Set(); 
     }); 
    } 

    public ManualResetEvent WaitHandle { get; private set; } 
} 

आपके मामले में यह XmlEditingScope.Complete यूआई धागा पर चलता है और ParseWaitHandle, जो सिर्फ व्यवहार आप से बचना चाहिए है पर इंतजार कर रहा है लगता है। ठीक करने के लिए, आप यूआई थ्रेड पर उपरोक्त कोड को निष्पादित करने से बचने का प्रयास कर सकते हैं, और इसके बजाय पृष्ठभूमि धागे पर चल सकते हैं।

+0

Evk, आपके उत्तर के लिए धन्यवाद। मैंने पृष्ठभूमि थ्रेड पर XmlEditingScope चलाने की कोशिश की है, लेकिन फिर मुझे एक सिस्टम मिलता है। एक्सेसऑलिलेशन अपवाद। Microsoft.VisualStudio.Shell.Interop.IVsQueryEditQuerySave2.QueryEditFiles (UInt32 rgfQueryEdit, Int32 cFiles, String [] rgpszMkDocuments, UInt32 [] rgrgf, VSQEQS_FILE_ATTRIBUTE_DATA [] rgFileInfo, UInt32 और pfEditVerdict, UInt32 और prgfMoreInfo) Microsoft.XmlEditor.Transaction.CanEditFilesInTransaction पर पर() Microsoft.XmlEditor.Transaction.PushToEditorTreeAndBuffer() Microsoft.XmlEditor.Transaction.Complete() – TWT

+0

अतिरिक्त जानकारी के बिना अधिक सलाह देने के लिए कड़ी मेहनत है। लेकिन कम से कम अब यह डेडलॉक नहीं है :) और क्या होगा यदि आप इसे यूआई थ्रेड पर भेज दें लेकिन डिस्पैचर के माध्यम से। बेगिन इनवोक (तो असीमित रूप से)? – Evk

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