You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I'm getting some crazy UI thread deadlocks after using AsyncEx.Context. WinForms app.
Here's the UI thread, doing UI things:
Application.Run(form);
Here's the sync context on this thread:
System.Windows.Forms.WindowsFormsSynchronizationContext, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 as expected.
However check this crazy callstack out:
System.dll!System.Collections.Concurrent.BlockingCollection<System.__Canon>.CheckDisposed() Line 1808 C#
System.dll!System.Collections.Concurrent.BlockingCollection<System.Tuple<System.Threading.Tasks.Task, bool>>.TryAddWithNoTimeValidation(System.Tuple<System.Threading.Tasks.Task, bool> item, int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) Line 414 C#
Nito.AsyncEx.Context.dll!Nito.AsyncEx.AsyncContext.TaskQueue.TryAdd(System.Threading.Tasks.Task item, bool propagateExceptions) Line 57 C#
Nito.AsyncEx.Context.dll!Nito.AsyncEx.AsyncContext.Enqueue(System.Threading.Tasks.Task task, bool propagateExceptions) Line 91 C#
mscorlib.dll!System.Threading.Tasks.Task.ScheduleAndStart(bool needsProtection) Line 1946 C#
mscorlib.dll!System.Threading.Tasks.Task.InternalStartNew(System.Threading.Tasks.Task creatingTask, System.Delegate action, object state, System.Threading.CancellationToken cancellationToken, System.Threading.Tasks.TaskScheduler scheduler, System.Threading.Tasks.TaskCreationOptions options, System.Threading.Tasks.InternalTaskOptions internalOptions, ref System.Threading.StackCrawlMark stackMark) Line 1294 C#
mscorlib.dll!System.Threading.Tasks.TaskFactory.StartNew(System.Action action, System.Threading.CancellationToken cancellationToken, System.Threading.Tasks.TaskCreationOptions creationOptions, System.Threading.Tasks.TaskScheduler scheduler) Line 401 C#
Nito.AsyncEx.Tasks.dll!Nito.AsyncEx.TaskFactoryExtensions.Run(System.Threading.Tasks.TaskFactory this, System.Action action) Unknown Nito.AsyncEx.Context.dll!Nito.AsyncEx.AsyncContext.AsyncContextSynchronizationContext.Send(System.Threading.SendOrPostCallback d, object state) Line 62 C#
System.dll!Microsoft.Win32.SystemEvents.SystemEventInvokeInfo.Invoke(bool checkFinalization, object[] args) Line 1634 C#
System.dll!Microsoft.Win32.SystemEvents.RaiseEvent(bool checkFinalization, object key, object[] args) Line 1314 C#
System.dll!Microsoft.Win32.SystemEvents.OnUserPreferenceChanged(int msg, System.IntPtr wParam, System.IntPtr lParam) Line 1006 C#
System.dll!Microsoft.Win32.SystemEvents**.WindowProc**(System.IntPtr hWnd, int msg, System.IntPtr wParam, System.IntPtr lParam) Line 1491 C#
The UI thread has somehow issued a post/send to an AsyncEx context which I use on other worker threads, but NEVER the UI thread! That Sync Context getting posted to has long been disposed, because this callstack ends in an exception thrown by the _queue in TaskQueue.cs:
System.ObjectDisposedException
HResult=0x80131622
Message=The collection has been disposed.
Object name: 'BlockingCollection'.
Source=System
StackTrace:
at System.Collections.Concurrent.BlockingCollection`1.CheckDisposed() in f:\dd\NDP\fx\src\sys\system\collections\concurrent\BlockingCollection.cs:line 1810
What I think is happening is that somehow a Control handle is being accidentally created on a non-UI thread, in which the Sync Context is AsyncEx's context. The control is auto-registering itself with SystemEvents to be notified when OnUserPreferenceChanged is raised. This registration also involves the current Sync Context, so it can post to it later.
The question is: How can I detect an erroneous handle creation on the non UI thread!
The text was updated successfully, but these errors were encountered:
I think I've figured it out, was me being an idiot. I was on the UI thread doing this unintentionally
AsyncContext.Run(() =>
{
// Create UI control here!
});
This meant that when some UI controls registered for OnUserPreferenceChanged callbacks, they passed the AsyncContext to it, saying "call me back on this context" - which was long since disposed. I've fixed my code so that I don't use AsyncContext.Run if I'm on the UI thread (doh)
I'm getting some crazy UI thread deadlocks after using AsyncEx.Context. WinForms app.
Here's the UI thread, doing UI things:
Application.Run(form);
Here's the sync context on this thread:
System.Windows.Forms.WindowsFormsSynchronizationContext, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 as expected.
However check this crazy callstack out:
System.dll!System.Collections.Concurrent.BlockingCollection<System.__Canon>.CheckDisposed() Line 1808 C#
System.dll!System.Collections.Concurrent.BlockingCollection<System.Tuple<System.Threading.Tasks.Task, bool>>.TryAddWithNoTimeValidation(System.Tuple<System.Threading.Tasks.Task, bool> item, int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) Line 414 C#
Nito.AsyncEx.Context.dll!Nito.AsyncEx.AsyncContext.TaskQueue.TryAdd(System.Threading.Tasks.Task item, bool propagateExceptions) Line 57 C#
Nito.AsyncEx.Context.dll!Nito.AsyncEx.AsyncContext.Enqueue(System.Threading.Tasks.Task task, bool propagateExceptions) Line 91 C#
mscorlib.dll!System.Threading.Tasks.Task.ScheduleAndStart(bool needsProtection) Line 1946 C#
mscorlib.dll!System.Threading.Tasks.Task.InternalStartNew(System.Threading.Tasks.Task creatingTask, System.Delegate action, object state, System.Threading.CancellationToken cancellationToken, System.Threading.Tasks.TaskScheduler scheduler, System.Threading.Tasks.TaskCreationOptions options, System.Threading.Tasks.InternalTaskOptions internalOptions, ref System.Threading.StackCrawlMark stackMark) Line 1294 C#
mscorlib.dll!System.Threading.Tasks.TaskFactory.StartNew(System.Action action, System.Threading.CancellationToken cancellationToken, System.Threading.Tasks.TaskCreationOptions creationOptions, System.Threading.Tasks.TaskScheduler scheduler) Line 401 C#
Nito.AsyncEx.Tasks.dll!Nito.AsyncEx.TaskFactoryExtensions.Run(System.Threading.Tasks.TaskFactory this, System.Action action) Unknown
Nito.AsyncEx.Context.dll!Nito.AsyncEx.AsyncContext.AsyncContextSynchronizationContext.Send(System.Threading.SendOrPostCallback d, object state) Line 62 C#
System.dll!Microsoft.Win32.SystemEvents.SystemEventInvokeInfo.Invoke(bool checkFinalization, object[] args) Line 1634 C#
System.dll!Microsoft.Win32.SystemEvents.RaiseEvent(bool checkFinalization, object key, object[] args) Line 1314 C#
System.dll!Microsoft.Win32.SystemEvents.OnUserPreferenceChanged(int msg, System.IntPtr wParam, System.IntPtr lParam) Line 1006 C#
System.dll!Microsoft.Win32.SystemEvents**.WindowProc**(System.IntPtr hWnd, int msg, System.IntPtr wParam, System.IntPtr lParam) Line 1491 C#
The UI thread has somehow issued a post/send to an AsyncEx context which I use on other worker threads, but NEVER the UI thread! That Sync Context getting posted to has long been disposed, because this callstack ends in an exception thrown by the _queue in TaskQueue.cs:
System.ObjectDisposedException
HResult=0x80131622
Message=The collection has been disposed.
Object name: 'BlockingCollection'.
Source=System
StackTrace:
at System.Collections.Concurrent.BlockingCollection`1.CheckDisposed() in f:\dd\NDP\fx\src\sys\system\collections\concurrent\BlockingCollection.cs:line 1810
It's very similar to this issue:
https://ikriv.com/dev/dotnet/MysteriousHang#WhatToDo
Which is also related to OnUserPreferenceChanged.
What I think is happening is that somehow a Control handle is being accidentally created on a non-UI thread, in which the Sync Context is AsyncEx's context. The control is auto-registering itself with SystemEvents to be notified when OnUserPreferenceChanged is raised. This registration also involves the current Sync Context, so it can post to it later.
The question is: How can I detect an erroneous handle creation on the non UI thread!
The text was updated successfully, but these errors were encountered: