2016-04-08 22 views
9

Visual Studio Uzantısında bir xml belgesini değiştirmek için Microsoft.VisualStudio.XmlEditor ad alanında (https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.xmleditor.aspx) sınıfları kullanıyoruz.VSIX - XmlEditingScope.Complete üzerinde kilitlenme()

Bazı nedenlerle, XmlEditingScope.Complete() yöntemini çağırarak bir kilitlenme oluşur.

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 

Ve Visual Studio: Visual Studio'nun statusbar, biz mesajı "ayrıştırma tamamlamak için bekleniyor ..." Bu yığın çıkmaz UI iş parçacığı izi olan

bkz ayrıştırmak thread:

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] 

burada tüm ilgili kod göstermek kolay değil, ama temelde bir WPF DataGrid denetiminde bir değişiklikten sonra yürütülür sadece aşağıdaki kod (IEditableObject.EndEdit ViewModel'de):

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

     s.Complete(); 
} 

Bu çıkmazın oluşmasını önlemek için ne yapabilirim? Değişiklikleri uygulamadan önce bir şeyi kilitlemem gerekir mi? Başka ne yanlış yapabilirim?

cevap

0

Daha fazla bir yorum ancak bir yorum alanına sığmadı. Bu durumun sizin durumunuzda niçin gerçekleştiğinin tam olarak nedenini söylemek ya da verdiğiniz bilgilerle düzeltmenin bir yolunu belirtmek zordur (daha fazla yardım sağlamak için, sadece çalışıp sorunu görebildiğimiz en az bir örneğe ihtiyacımız var). Bununla birlikte, yığınlar bunun, "tek iş parçacıklı" doğaları nedeniyle neredeyse tüm UI çerçevelerinde sıklıkla meydana gelen düzenli UI kilitlenme olduğunu gösterir (tüm UI öğeleriyle tüm eylemler tek bir iş parçacığında gerçekleşmelidir). Iş parçacığı A (bu durumda görsel stüdyo ayrıştırma iş parçacığı) arka plan iş parçacığı UI iş parçacığı sırasına bir görev gönderir ve tamamlamak için bekler (örneğin tam olarak bunu yapan WPF Dispatcher.Invoke çağrı). Tüm görevin, kilitlenmenin gerçekleşmesi için UI iş parçacığı üzerinde yürütülmesi gerekli değildir, yalnızca bir kısmı (örneğin, UI denetiminden gerçek xml al) yeterlidir. Sonra aynı şeyi UI iş parçacığının üzerinde yapıyorsunuz. Bu, beklemede UI iş parçacığında bir beklemede beklemenizdir (UI iş parçacığı üzerindeki kilit ifadeleri aynı kategoriye girer). Bu son derece tehlikelidir ve bu durumda muhtemelen (muhtemelen) kilitlenmelere yol açar.

Ben bu küçük örnekte (WPF) ile benim açımdan göstermek olacaktır: Senin durumunda

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; } 
} 

o XmlEditingScope.Complete UI iş parçacığı üzerinde çalışır ve kaçınmalısınız sadece bir davranıştır ParseWaitHandle, üzerinde bekler gibi görünüyor. Düzeltmek için, yukarıdaki kodun UI iş parçacığı üzerinde yürütülmesini önleyebilir ve bunun yerine arka plan iş parçacığı üzerinde çalışabilirsiniz.

+0

Evk, cevabınız için teşekkürler. Bir arka plan iş parçacığı üzerinde XmlEditingScope çalıştırmayı denedim, ancak sonra bir System.AccessViolationException alıyorum. Microsoft.XmlEditor.Transaction.CanEditFilesInTransaction de Microsoft.VisualStudio.Shell.Interop.IVsQueryEditQuerySave2.QueryEditFiles (Uınt32 rgfQueryEdit, ınt32 cFiles, String [] rgpszMkDocuments, Uınt32 [] rgrgf, VSQEQS_FILE_ATTRIBUTE_DATA [] rgFileInfo, Uınt32 ve pfEditVerdict, Uınt32 ve prgfMoreInfo) de () Microsoft.XmlEditor.Transaction.PushToEditorTreeAndBuffer() at Microsoft.XmlEditor.Transaction.Complete() – TWT

+0

Ek bilgi olmadan daha fazla öneri vermek çok zor. Ama en azından şimdi kilitlenme değil :) Ve eğer UI iş parçacığına ancak Dispatcher.BeginInvoke (eşzamansız) yoluyla gönderirseniz? – Evk