TWT*_*TWT 9 c# deadlock visual-studio vsix visual-studio-extensions
我们使用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
Run Code Online (Sandbox Code Playgroud)
并且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]
Run Code Online (Sandbox Code Playgroud)
在这里显示所有相关代码并不容易,但基本上它只是在WPF DataGrid控件(ViewModel中的IEditableObject.EndEdit)中更改后执行的以下代码:
using (var s = store.BeginEditingScope("Test", null))
{
apply changes in xmlModel.Document...
s.Complete();
}
Run Code Online (Sandbox Code Playgroud)
我该怎么做才能防止这种僵局的发生.在应用更改之前,我是否需要锁定某些内容?还有什么我可能做错了?
这更像是一条评论,但不适合评论字段。很难说出在您的情况下发生这种情况的确切原因,也很难仅使用您提供的信息来提供修复它的方法(为了提供更多帮助,我们需要最小的示例,我们可以运行并查看问题)。然而,堆栈跟踪显示这是常规的 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; }
}
Run Code Online (Sandbox Code Playgroud)
在您的情况下,似乎 XmlEditingScope.Complete 在 UI 线程上运行并等待 ParseWaitHandle,这只是您应该避免的行为。要解决此问题,您可以尝试避免在 UI 线程上执行上面的代码,而是在后台线程上运行。
| 归档时间: |
|
| 查看次数: |
162 次 |
| 最近记录: |