gpt4 book ai didi

c# - VSIX - XmlEditingScope.Complete() 上的死锁

转载 作者:太空狗 更新时间:2023-10-29 18:00:01 24 4
gpt4 key购买 nike

我们正在使用 Microsoft.VisualStudio.XmlEditor 命名空间 ( https://msdn.microsoft.com/en-us/library/microsoft.visualstudio.xmleditor.aspx ) 中的类来修改 Visual Studio 扩展中的 xml 文档。

由于某种原因,在调用 XmlEditingScope.Complete() 后发生死锁方法。在 Visual Studio 的状态栏中,我们看到消息“等待解析完成...”

这是死锁 UI 线程的堆栈跟踪:

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

以及 Visual Studio 解析线程:

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 DataGrid 控件(ViewModel 中的 IEditableObject.EndEdit)后执行的以下代码:

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

s.Complete();
}

我该怎么做才能避免这种僵局的发生。在应用更改之前我需要锁定某些内容吗?我还能做错什么吗?

最佳答案

它更像是一条评论,但不适合评论字段。很难说出在您的案例中发生这种情况的确切原因,也很难仅使用您提供的信息提供修复它的方法(为了提供更多帮助,我们需要最少的示例,我们可以运行它并查看问题)。但是,堆栈跟踪显示这是常规的 UI 死锁,由于其“单线程”性质(所有 UI 元素的大多数操作必须在单线程上发生),几乎所有 UI 框架中经常发生这种死锁。线程 A(在本例中为 visual studio 解析线程)从后台线程向 UI 线程队列发布任务并等待它完成(例如 WPF Dispatcher.Invoke 调用就是这样做的)。没有必要在 UI 线程上执行整个任务才能发生死锁,只需执行其中的一部分(例如 - 从 UI 控件获取实际的 xml)就足够了。然后你在 UI 线程本身上做同样的事情。也就是说,您等待 UI 线程中的某个等待句柄(在 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 似乎在 UI 线程上运行并等待 ParseWaitHandle,这是您应该避免的行为。要解决此问题,您可以尝试避免在 UI 线程上执行上述代码,而是在后台线程上运行。

关于c# - VSIX - XmlEditingScope.Complete() 上的死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36493764/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com