【发布时间】:2011-06-07 06:03:39
【问题描述】:
我的应用程序有一个问题:在某些时候,主线程的 SynchronizationContext.Current 变为 null。我无法在一个孤立的项目中重现同样的问题。我的实际项目很复杂;它混合了 Windows 窗体和 WPF 并调用 WCF Web 服务。据我所知,这些都是可能与 SynchronizationContext 交互的系统。
这是我独立项目的代码。我真正的应用程序做了类似的事情。但是,在我的真实应用程序中,当执行延续任务时,主线程上的 SynchronizationContext.Current 为 null。
private void button2_Click(object sender, EventArgs e)
{
if (SynchronizationContext.Current == null)
{
Debug.Fail("SynchronizationContext.Current is null");
}
Task.Factory.StartNew(() =>
{
CallWCFWebServiceThatThrowsAnException();
})
.ContinueWith((t) =>
{
//update the UI
UpdateGUI(t.Exception);
if (SynchronizationContext.Current == null)
{
Debug.Fail("SynchronizationContext.Current is null");
}
}, CancellationToken.None,
TaskContinuationOptions.OnlyOnFaulted,
TaskScheduler.FromCurrentSynchronizationContext());
}
什么可能导致主线程的 SynchronizationContext.Current 变为 null?
编辑:
@Hans 请求堆栈跟踪。这里是:
在 d:\sources\s2\Framework\Sources\UI\Commands\AsyncCommand.cs:line 157 中的 MyApp.Framework.UI.Commands.AsyncCommand.HandleTaskError(任务任务) 在 System.Threading.Tasks.Task.c__DisplayClassb.b__a(对象 obj) 在 System.Threading.Tasks.Task.InnerInvoke() 在 System.Threading.Tasks.Task.Execute() 在 System.Threading.Tasks.Task.ExecutionContextCallback(对象 obj) 在 System.Threading.ExecutionContext.runTryCode(对象 userData) 在 System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode 代码,CleanupCode backoutCode,对象 userData) 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext,ContextCallback 回调,对象状态) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态,布尔 ignoreSyncCtx) 在 System.Threading.Tasks.Task.ExecuteWithThreadLocal(任务和 currentTaskSlot) 在 System.Threading.Tasks.Task.ExecuteEntry(布尔 bPreventDoubleExecution) 在 System.Threading.Tasks.SynchronizationContextTaskScheduler.PostCallback(对象 obj) 在 System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo 方法,对象目标,Object[] 参数,SignatureStruct& sig,MethodAttributes methodAttributes,RuntimeType typeOwner) 在 System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo 方法,对象目标,对象 [] 参数,签名 sig,MethodAttributes 方法属性,RuntimeType typeOwner) 在 System.Reflection.RuntimeMethodInfo.Invoke(Object obj,BindingFlags invokeAttr,Binder binder,Object[] 参数,CultureInfo 文化,布尔型 skipVisibilityChecks) 在 System.Delegate.DynamicInvokeImpl(对象 [] 参数) 在 System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry 时间) 在 System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(对象 obj) 在 System.Threading.ExecutionContext.runTryCode(对象 userData) 在 System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode 代码,CleanupCode backoutCode,对象 userData) 在 System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext,ContextCallback 回调,对象状态) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态,布尔 ignoreSyncCtx) 在 System.Threading.ExecutionContext.Run(ExecutionContext executionContext,ContextCallback 回调,对象状态) 在 System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry 时间) 在 System.Windows.Forms.Control.InvokeMarshaledCallbacks() 在 System.Windows.Forms.Control.WndProc(消息和 m) 在 System.Windows.Forms.Control.ControlNativeWindow.OnMessage(消息& m) 在 System.Windows.Forms.Control.ControlNativeWindow.WndProc(消息和 m) 在 System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd,Int32 msg,IntPtr wparam,IntPtr lparam) 在 System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(味精和味精) 在 System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID,Int32 原因,Int32 pvLoopData) 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 原因,ApplicationContext 上下文) 在 System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 原因,ApplicationContext 上下文) 在 System.Windows.Forms.Application.Run(窗体 mainForm) 在 d:\sources\s2\Framework\Sources\UI\SharedUI\ApplicationBase.cs:line 190 中的 MyApp.Framework.SharedUI.ApplicationBase.InternalStart() 在 d:\sources\s2\Framework\Sources\UI\SharedUI\ApplicationBase.cs:line 118 中的 MyApp.Framework.SharedUI.ApplicationBase.Start() 在 d:\sources\s2\App1\Sources\WinUI\HDA.cs:line 63 中的 MyApp.App1.WinUI.HDA.Main()【问题讨论】:
-
在 UpdateGUI 上设置断点并发布堆栈跟踪。
-
看起来完全正常。我无法解释为什么 TaskScheduler.FromCurrentSynchronizationContext() 不起作用。这是为 Control.InvokeMarshaledCallback() 调用提供 SC 的那个。它已经检查了空值。假设您使用的是 .NET 4.0
-
“Dispatcher”,你是在混合 Winforms 和 WPF 代码吗?
-
@Sly 你得到这个问题的答案了吗?我在这里遇到同样的问题>.
-
@MichelAyres:我们从未找到根本原因,因此决定通过将
SynchronizationContext.Current复制到_syncContext变量来解决此问题。然后,在任务回调中我们执行if (SynchronizationContext.Current == null) { SynchronizationContext.SetSynchronizationContext(_syncContext); }。你看过@Dan的回答吗?我从来没有尝试过,这就是为什么我还没有接受他的回答。如果您使用 .Net 4.5 对其进行测试并且如果它有效,请告诉我,我会接受 Dan 的回答。
标签: c# wpf winforms task-parallel-library