WPF application hang by PropertyChangedEventManager in concurrent environments
c#, inotifypropertychanged, multithreading, propertychanged, wpf
Solution
I've finally fix the issue after digging into the source code of almost all the related components. Thanks to the fantastic Reference Source web site, the comments in source code help a lot comparing to the de-compiled result from ILSpy.
What's `PropertyChangedEventManager`?
`PropertyChangedEventManager` (source code here) is a component that handles the `ProperyChanged` event handlers and notifications in a concurrent environment. In the other words, it's thread-safe. Internally it uses a `ReaderWriterLock` to keep the thread safety. The writer lock would be acquired when the event handlers are being changed, and the reader lock would be acquired when there're `PropertyChanged` event notifications.
`PropertyChangedEventManager` is normally used by WPF controls. When we attach/detach the view model to the control, we're adding/removing `PropertyChanged` event handlers. I was always wondering who's holding the writer lock which blocks the reader lock (`get_ReadLock`), but actually it's the GUI thread itself.
Yes it sounds weird but it is just inside `PrivateAddListener` (source code here) as the stacktrace shows:
...
[IL Method without Metadata]
66. WindowsBase.dll#0!System.ComponentModel.PropertyChangedEventManager.PrivateAddListener(source=<N/A>, listener=<N/A>, propertyName=<N/A>) (source line information unavailable)
67. PresentationFramework.dll#0!MS.Internal.Data.PropertyPathWorker.ReplaceItem(k=<N/A>, newO=<N/A>, parent=<N/A>) (source line information unavailable)
...
BTW, I was always told that we should fire `PropertyChanged` event in an UI-bound object from background thread, but it's not the case since .NET 4. `PropertyChangedEventManager` is designed to be used in a concurrent environment. The exclusive (writer) lock would be used only when the model is binding to the GUI control, and the `PropertyChanged` event could be trigger from multiple background threads concurrently. We don't need to marshal everything to the GUI thread manually.
Actually it's a very important pattern to update models in background thread, and sometimes that's the only acceptable approach. Please consider the case that when we have multiple GUI/STA threads to improve the responsiveness of the application. We could bind the same instance to the controls in different GUI thread. When the model is changed, we simply cannot marshal the `PropertyChanged` notification into any one of them. Cross threading notification is inevitable.
What's `SubclassWndProc`?
`HwndSubclass.SubclassWndProc` (source code here) is the entry point of managed code to handle window messages. It's called by native code so we could always find `[IL Method without Metadata]` and `[Internal Frame, 'M-->U']` before it in the stacktrace.
The weird thing is, why there would be several `SubclassWndProc` calls in the stacktrace? Shouldn't the window messages be processed one after another, separately? To answer the question, we need to check the code of the methods appears repeatedly in the stacktrace:
...
55. PresentationFramework.dll#0!System.Windows.Window.HandleActivate(windowActivated=<N/A>) (source line information unavailable)
56. PresentationFramework.dll#0!System.Windows.Window.WmActivate(wParam=<N/A>) (source line information unavailable)
57. PresentationFramework.dll#0!System.Windows.Window.WindowFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>) (source line information unavailable)
...
From the source code I noticed that these methods are dealing with `WM_ACTIVATE` message (OK we could also tell it from the name). It's a special message as decribed in MSDN:
Sent to both the window being activated and the window being deactivated. If the windows use the same input queue, the message is sent synchronously, first to the window procedure of the top-level window being deactivated, then to the window procedure of the top-level window being activated. If the windows use different input queues, the message is sent asynchronously, so the window is activated immediately.
Since the message is sent synchronously in GUI thread, it would be processed immediately without finishing the current one. That's the reason we could find recursive calls in the stacktrace.
It also explains why `WindowViewMode.IsActive` is set multiple times:
- in #47 - `WindowViewModel.set_IsActive(value=True)`
- in #25 - `WindowViewModel.set_IsActive(value=False)`
- in #3 - `WindowViewModel.set_IsActive(value=True)`
Since it would be "deactivated" and "activated" again.
Root cause and solution
In `WindowViewModel` we have an `IsActive` property which is synchronized with `Window.IsActive` property. Please note it's not two-way binding since the property is read-only. When the window is activated, `WindowViewModel.IsActive` property would be set and trigger the `PropertyChanged` event. Since the WPF control has been hooked up with the view model, so the internal logic is executed.
I'm not clear what the logic is in detail (it's `[IL Method without Metadata]`) but unfortunately it produces a new `WM_ACTIVATE` message. This happens again and again and finally stop the GUI thread.
After making sure we're not using `WindowViewModel.IsActive` in binding, I changed it to the `IsActive()` method. We don't need to trigger the `PropertyChanged` event since it's not a property anymore.
I also left a comment said that if we do require `IsActive` to be a property, we need to make sure the `PropertyChanged` event is triggered inside `Dispatcher.BeginInvoke`, even it's already in the GUI thread. We need to make sure the next `WM_ACTIVATE` message is produced asynchronously.
One thing I cannot explain
But I still cannot explain why the `ReaderWriterLock` would block when we're acquiring the reader lock for the third or fourth time. I do think we have deeper recursive `PropertyChanged` notifications so the reader lock would be acquired more times than the current case. But every time we run into this issue, we always have the `IsActive` property in the stack trace.
Is there any special protection in `ReaderWriterLock` or WPF or even in the OS?
Problem
I'm working on a complex WPF application which hangs in production once several days. There's a thread other than GUI thread filling data to models bind to the grid and triggers `INotifyPropertyChanged.PropertyChanged` event. I wrote a script to attach MDbg to the hanging process and dumping the current stack trace of the threads. It helps a lot when finding the cause of deadlock but it doesn't help this time. The thread which is updating models is stopped at acquiring `ReadLock`: ``` Thread [#:8] *0. WindowsBase.dll#0!MS.Internal.ReaderWriterLockWrapper.get_ReadLock() (source line information unavailable) 1. WindowsBase.dll#0!System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(sender=<...>, args=System.ComponentModel.PropertyChangedEventArgs) (source line information unavailable) 2. ( ... firing PropertyChanged event ... ) ``` The same thing happens to the GUI thread: ``` Thread [#:0] *0. WindowsBase.dll#0!MS.Internal.ReaderWriterLockWrapper.get_ReadLock() (source line information unavailable) 1. WindowsBase.dll#0!System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(sender=MyCompany.Windows.ViewModel.Window.WindowViewModel, args=System.ComponentModel.PropertyChangedEventArgs) (source line information unavailable) 2. MyCompany.Windows.Contracts.dll#0!MyCompany.Windows.ViewModel.Model.ViewModelItemBase.NotifyPropertyChanged(propertyName="IsActive") (source line information unavailable) 3. MyCompany.Windows.Contracts.dll#0!MyCompany.Windows.ViewModel.Window.WindowViewModel.set_IsActive(value=True) (source line information unavailable) 4. MyCompany.Windows.dll#0!MyCompany.Windows.ViewModel.Window.IsActiveBinding.OnWindowIsActiveChanged(sender=MyCompany.Xpf.Views.XpfRibbonShell.XpfRibbonShellView, e=System.EventArgs) (source line information unavailable) 5. WindowsBase.dll#0!MS.Internal.ComponentModel.PropertyChangeTracker.OnPropertyInvalidation(d=<N/A>, args=<N/A>) (source line information unavailable) 6. WindowsBase.dll#0!System.Windows.DependentList.InvalidateDependents(source=<N/A>, sourceArgs=<N/A>) (source line information unavailable) 7. WindowsBase.dll#0!System.Windows.DependencyObject.NotifyPropertyChange(args=<N/A>) (source line information unavailable) 8. WindowsBase.dll#0!System.Windows.DependencyObject.UpdateEffectiveValue(entryIndex=<N/A>, dp=<N/A>, metadata=<N/A>, oldEntry=<N/A>, newEntry=<N/A>, coerceWithDeferredReference=<N/A>, coerceWithCurrentValue=<N/A>, operationType=<N/A>) (source line information unavailable) 9. WindowsBase.dll#0!System.Windows.DependencyObject.SetValueCommon(dp=<N/A>, value=<N/A>, metadata=<N/A>, coerceWithDeferredReference=<N/A>, coerceWithCurrentValue=<N/A>, operationType=<N/A>, isInternal=<N/A>) (source line information unavailable) 10. WindowsBase.dll#0!System.Windows.DependencyObject.SetValue(key=<N/A>, value=<N/A>) (source line information unavailable) 11. PresentationFramework.dll#0!System.Windows.Window.HandleActivate(windowActivated=<N/A>) (source line information unavailable) 12. PresentationFramework.dll#0!System.Windows.Window.WmActivate(wParam=<N/A>) (source line information unavailable) 13. PresentationFramework.dll#0!System.Windows.Window.WindowFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>) (source line information unavailable) 14. PresentationCore.dll#0!System.Windows.Interop.HwndSource.PublicHooksFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>) (source line information unavailable) 15. WindowsBase.dll#0!MS.Win32.HwndWrapper.WndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>) (source line information unavailable) 16. WindowsBase.dll#0!MS.Win32.HwndSubclass.DispatcherCallbackOperation(o=<N/A>) (source line information unavailable) 17. WindowsBase.dll#0!System.Windows.Threading.ExceptionWrapper.InternalRealCall(callback=<N/A>, args=<N/A>, numArgs=<N/A>) (source line information unavailable) 18. WindowsBase.dll#0!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(source=System.Windows.Threading.Dispatcher, method=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<null>) (source line information unavailable) 19. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.WrappedInvoke(callback=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<N/A>) (source line information unavailable) 20. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.InvokeImpl(priority=<N/A>, timeout=<N/A>, method=<N/A>, args=<N/A>, numArgs=<N/A>) (source line information unavailable) 21. WindowsBase.dll#0!MS.Win32.HwndSubclass.SubclassWndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>) (source line information unavailable) [IL Method without Metadata] 22. WindowsBase.dll#0!MS.Internal.ReaderWriterLockWrapper.get_ReadLock() (source line information unavailable) 23. WindowsBase.dll#0!System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(sender=MyCompany.Windows.ViewModel.Window.WindowViewModel, args=System.ComponentModel.PropertyChangedEventArgs) (source line information unavailable) 24. MyCompany.Windows.Contracts.dll#0!MyCompany.Windows.ViewModel.Model.ViewModelItemBase.NotifyPropertyChanged(propertyName="IsActive") (source line information unavailable) 25. MyCompany.Windows.Contracts.dll#0!MyCompany.Windows.ViewModel.Window.WindowViewModel.set_IsActive(value=False) (source line information unavailable) 26. MyCompany.Windows.dll#0!MyCompany.Windows.ViewModel.Window.IsActiveBinding.OnWindowIsActiveChanged(sender=MyCompany.Xpf.Views.XpfRibbonShell.XpfRibbonShellView, e=System.EventArgs) (source line information unavailable) 27. WindowsBase.dll#0!MS.Internal.ComponentModel.PropertyChangeTracker.OnPropertyInvalidation(d=<N/A>, args=<N/A>) (source line information unavailable) 28. WindowsBase.dll#0!System.Windows.DependentList.InvalidateDependents(source=<N/A>, sourceArgs=<N/A>) (source line information unavailable) 29. WindowsBase.dll#0!System.Windows.DependencyObject.NotifyPropertyChange(args=<N/A>) (source line information unavailable) 30. WindowsBase.dll#0!System.Windows.DependencyObject.UpdateEffectiveValue(entryIndex=<N/A>, dp=<N/A>, metadata=<N/A>, oldEntry=<N/A>, newEntry=<N/A>, coerceWithDeferredReference=<N/A>, coerceWithCurrentValue=<N/A>, operationType=<N/A>) (source line information unavailable) 31. WindowsBase.dll#0!System.Windows.DependencyObject.SetValueCommon(dp=<N/A>, value=<N/A>, metadata=<N/A>, coerceWithDeferredReference=<N/A>, coerceWithCurrentValue=<N/A>, operationType=<N/A>, isInternal=<N/A>) (source line information unavailable) 32. WindowsBase.dll#0!System.Windows.DependencyObject.SetValue(key=<N/A>, value=<N/A>) (source line information unavailable) 33. PresentationFramework.dll#0!System.Windows.Window.HandleActivate(windowActivated=<N/A>) (source line information unavailable) 34. PresentationFramework.dll#0!System.Windows.Window.WmActivate(wParam=<N/A>) (source line information unavailable) 35. PresentationFramework.dll#0!System.Windows.Window.WindowFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>) (source line information unavailable) 36. PresentationCore.dll#0!System.Windows.Interop.HwndSource.PublicHooksFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>) (source line information unavailable) 37. WindowsBase.dll#0!MS.Win32.HwndWrapper.WndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>) (source line information unavailable) 38. WindowsBase.dll#0!MS.Win32.HwndSubclass.DispatcherCallbackOperation(o=<N/A>) (source line information unavailable) 39. WindowsBase.dll#0!System.Windows.Threading.ExceptionWrapper.InternalRealCall(callback=<N/A>, args=<N/A>, numArgs=<N/A>) (source line information unavailable) 40. WindowsBase.dll#0!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(source=System.Windows.Threading.Dispatcher, method=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<null>) (source line information unavailable) 41. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.WrappedInvoke(callback=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<N/A>) (source line information unavailable) 42. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.InvokeImpl(priority=<N/A>, timeout=<N/A>, method=<N/A>, args=<N/A>, numArgs=<N/A>) (source line information unavailable) 43. WindowsBase.dll#0!MS.Win32.HwndSubclass.SubclassWndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>) (source line information unavailable) [IL Method without Metadata] 44. WindowsBase.dll#0!MS.Internal.ReaderWriterLockWrapper.get_ReadLock() (source line information unavailable) 45. WindowsBase.dll#0!System.ComponentModel.PropertyChangedEventManager.OnPropertyChanged(sender=MyCompany.Windows.ViewModel.Window.WindowViewModel, args=System.ComponentModel.PropertyChangedEventArgs) (source line information unavailable) 46. MyCompany.Windows.Contracts.dll#0!MyCompany.Windows.ViewModel.Model.ViewModelItemBase.NotifyPropertyChanged(propertyName="IsActive") (source line information unavailable) 47. MyCompany.Windows.Contracts.dll#0!MyCompany.Windows.ViewModel.Window.WindowViewModel.set_IsActive(value=True) (source line information unavailable) 48. MyCompany.Windows.dll#0!MyCompany.Windows.ViewModel.Window.IsActiveBinding.OnWindowIsActiveChanged(sender=MyCompany.Xpf.Views.XpfRibbonShell.XpfRibbonShellView, e=System.EventArgs) (source line information unavailable) 49. WindowsBase.dll#0!MS.Internal.ComponentModel.PropertyChangeTracker.OnPropertyInvalidation(d=<N/A>, args=<N/A>) (source line information unavailable) 50. WindowsBase.dll#0!System.Windows.DependentList.InvalidateDependents(source=<N/A>, sourceArgs=<N/A>) (source line information unavailable) 51. WindowsBase.dll#0!System.Windows.DependencyObject.NotifyPropertyChange(args=<N/A>) (source line information unavailable) 52. WindowsBase.dll#0!System.Windows.DependencyObject.UpdateEffectiveValue(entryIndex=<N/A>, dp=<N/A>, metadata=<N/A>, oldEntry=<N/A>, newEntry=<N/A>, coerceWithDeferredReference=<N/A>, coerceWithCurrentValue=<N/A>, operationType=<N/A>) (source line information unavailable) 53. WindowsBase.dll#0!System.Windows.DependencyObject.SetValueCommon(dp=<N/A>, value=<N/A>, metadata=<N/A>, coerceWithDeferredReference=<N/A>, coerceWithCurrentValue=<N/A>, operationType=<N/A>, isInternal=<N/A>) (source line information unavailable) 54. WindowsBase.dll#0!System.Windows.DependencyObject.SetValue(key=<N/A>, value=<N/A>) (source line information unavailable) 55. PresentationFramework.dll#0!System.Windows.Window.HandleActivate(windowActivated=<N/A>) (source line information unavailable) 56. PresentationFramework.dll#0!System.Windows.Window.WmActivate(wParam=<N/A>) (source line information unavailable) 57. PresentationFramework.dll#0!System.Windows.Window.WindowFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>) (source line information unavailable) 58. PresentationCore.dll#0!System.Windows.Interop.HwndSource.PublicHooksFilterMessage(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>) (source line information unavailable) 59. WindowsBase.dll#0!MS.Win32.HwndWrapper.WndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>) (source line information unavailable) 60. WindowsBase.dll#0!MS.Win32.HwndSubclass.DispatcherCallbackOperation(o=<N/A>) (source line information unavailable) 61. WindowsBase.dll#0!System.Windows.Threading.ExceptionWrapper.InternalRealCall(callback=<N/A>, args=<N/A>, numArgs=<N/A>) (source line information unavailable) 62. WindowsBase.dll#0!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(source=System.Windows.Threading.Dispatcher, method=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<null>) (source line information unavailable) 63. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.WrappedInvoke(callback=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<N/A>) (source line information unavailable) 64. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.InvokeImpl(priority=<N/A>, timeout=<N/A>, method=<N/A>, args=<N/A>, numArgs=<N/A>) (source line information unavailable) 65. WindowsBase.dll#0!MS.Win32.HwndSubclass.SubclassWndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>) (source line information unavailable) [IL Method without Metadata] 66. WindowsBase.dll#0!System.ComponentModel.PropertyChangedEventManager.PrivateAddListener(source=<N/A>, listener=<N/A>, propertyName=<N/A>) (source line information unavailable) 67. PresentationFramework.dll#0!MS.Internal.Data.PropertyPathWorker.ReplaceItem(k=<N/A>, newO=<N/A>, parent=<N/A>) (source line information unavailable) 68. PresentationFramework.dll#0!MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(k=<N/A>, collectionView=<N/A>, newValue=<N/A>, isASubPropertyChange=<N/A>) (source line information unavailable) 69. PresentationFramework.dll#0!MS.Internal.Data.ClrBindingWorker.AttachDataItem() (source line information unavailable) 70. PresentationFramework.dll#0!System.Windows.Data.BindingExpression.Activate(item=<N/A>) (source line information unavailable) 71. PresentationFramework.dll#0!System.Windows.Data.BindingExpression.AttachToContext(attempt=<N/A>) (source line information unavailable) 72. PresentationFramework.dll#0!System.Windows.Data.BindingExpression.MS.Internal.Data.IDataBindEngineClient.AttachToContext(lastChance=<N/A>) (source line information unavailable) 73. PresentationFramework.dll#0!MS.Internal.Data.DataBindEngine+Task.Run(lastChance=<N/A>) (source line information unavailable) 74. PresentationFramework.dll#0!MS.Internal.Data.DataBindEngine.Run(arg=<N/A>) (source line information unavailable) 75. PresentationFramework.dll#0!MS.Internal.Data.DataBindEngine.OnLayoutUpdated(sender=<N/A>, e=<N/A>) (source line information unavailable) 76. PresentationCore.dll#0!System.Windows.ContextLayoutManager.fireLayoutUpdateEvent() (source line information unavailable) 77. PresentationCore.dll#0!System.Windows.ContextLayoutManager.UpdateLayout() (source line information unavailable) 78. PresentationCore.dll#0!System.Windows.ContextLayoutManager.UpdateLayoutCallback(arg=<N/A>) (source line information unavailable) 79. PresentationCore.dll#0!System.Windows.Media.MediaContext.FireInvokeOnRenderCallbacks() (source line information unavailable) 80. PresentationCore.dll#0!System.Windows.Media.MediaContext.RenderMessageHandlerCore(resizedCompositionTarget=<N/A>) (source line information unavailable) 81. PresentationCore.dll#0!System.Windows.Media.MediaContext.RenderMessageHandler(resizedCompositionTarget=<N/A>) (source line information unavailable) 82. WindowsBase.dll#0!System.Windows.Threading.ExceptionWrapper.InternalRealCall(callback=<N/A>, args=<N/A>, numArgs=<N/A>) (source line information unavailable) 83. WindowsBase.dll#0!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(source=System.Windows.Threading.Dispatcher, method=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<null>) (source line information unavailable) 84. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.WrappedInvoke(callback=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<N/A>) (source line information unavailable) 85. WindowsBase.dll#0!System.Windows.Threading.DispatcherOperation.InvokeImpl() (source line information unavailable) 86. mscorlib.dll#0!System.Threading.ExecutionContext.runTryCode(userData=<N/A>) (source line information unavailable) 87. mscorlib.dll#0!System.Threading.ExecutionContext.Run(executionContext=<N/A>, callback=<N/A>, state=<N/A>, ignoreSyncCtx=<N/A>) (source line information unavailable) 88. mscorlib.dll#0!System.Threading.ExecutionContext.Run(executionContext=<N/A>, callback=<N/A>, state=<N/A>) (source line information unavailable) 89. WindowsBase.dll#0!System.Windows.Threading.DispatcherOperation.Invoke() (source line information unavailable) 90. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.ProcessQueue() (source line information unavailable) 91. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.WndProcHook(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>) (source line information unavailable) 92. WindowsBase.dll#0!MS.Win32.HwndWrapper.WndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>, handled=<N/A>) (source line information unavailable) 93. WindowsBase.dll#0!MS.Win32.HwndSubclass.DispatcherCallbackOperation(o=<N/A>) (source line information unavailable) 94. WindowsBase.dll#0!System.Windows.Threading.ExceptionWrapper.InternalRealCall(callback=<N/A>, args=<N/A>, numArgs=<N/A>) (source line information unavailable) 95. WindowsBase.dll#0!MS.Internal.Threading.ExceptionFilterHelper.TryCatchWhen(source=System.Windows.Threading.Dispatcher, method=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<null>) (source line information unavailable) 96. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.WrappedInvoke(callback=<N/A>, args=<N/A>, numArgs=<N/A>, catchHandler=<N/A>) (source line information unavailable) 97. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.InvokeImpl(priority=<N/A>, timeout=<N/A>, method=<N/A>, args=<N/A>, numArgs=<N/A>) (source line information unavailable) 98. WindowsBase.dll#0!MS.Win32.HwndSubclass.SubclassWndProc(hwnd=<N/A>, msg=<N/A>, wParam=<N/A>, lParam=<N/A>) (source line information unavailable) [IL Method without Metadata] [Internal Frame, 'M-->U'] [IL Method without Metadata] 99. WindowsBase.dll#0!System.Windows.Threading.Dispatcher.PushFrameImpl(frame=<N/A>) (source line information unavailable) 100. PresentationFramework.dll#0!System.Windows.Application.RunInternal(window=<N/A>) (source line information unavailable) 101. PresentationFramework.dll#0!System.Windows.Application.Run() (source line information unavailable) 102. MyProgram.exe#0!XamlGeneratedNamespace.GeneratedApplication.Main() (source line information unavailable) ``` It seems that someone is holding the `WriteLock` but never release - but how can I check who's holding that? I've paste the whole stacktrace I've got here, is someone to give me some hits on the root cause, like what's `HwndSubclass` and why it happens repeatedly in the stacktrace with the change of `IsActive` and `WindowState` property? Please add comments if you need more information.