主线程的SynchronizationContext.Current如何在成为空Windows窗体应用程序? [英] How can SynchronizationContext.Current of the main thread become null in a Windows Forms application?

查看:742
本文介绍了主线程的SynchronizationContext.Current如何在成为空Windows窗体应用程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在我的应用程序的一个问题:在某些时候,SynchronizationContext.Current成为空主线程。我无法再现一个孤立的项目同样的问题。我真正的项目是复杂的;它混合了Windows窗体和WPF和WCF调用Web服务。据我所知,这些都是可以与交互的SynchronizationContext的所有系统。

这是从我的孤立的项目的code。我真正的应用程序做一些事情,类似于。然而,在我真正的应用程序的SynchronizationContext.Current是在执行任务,继续在主线程空。

 私人无效button2_Click(对象发件人,EventArgs的发送)
{
    如果(SynchronizationContext.Current == NULL)
    {
        Debug.Fail(SynchronizationContext.Current为空);
    }    Task.Factory.StartNew(()=>
    {
        CallWCFWebServiceThatThrowsAnException();
    })
    .ContinueWith((T)=>
    {        //更新UI
        UpdateGUI(t.Exception);        如果(SynchronizationContext.Current == NULL)
        {
            Debug.Fail(SynchronizationContext.Current为空);
        }    },CancellationToken.None,
       TaskContinuationOptions.OnlyOnFaulted,
       TaskScheduler.FromCurrentSynchronizationContext());
}

什么会导致主线程的SynchronizationContext.Current成为空?

编辑:

@Hans要求堆栈跟踪。在这里,它是:

   在MyApp.Framework.UI.Commands.AsyncCommand.HandleTaskError(任务任务)在d:\\来源\\ S2 \\框架\\来源\\ UI \\命令\\ AsyncCommand.cs:157线
   在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.runTry code(用户数据对象)
   在System.Runtime.CompilerServices.RuntimeHelpers.Execute codeWithGuaranteedCleanup(试行code code,清理code撤销code,对象用户数据)
   在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(布尔b preventDoubleExecution)
   在System.Threading.Tasks.SynchronizationContextTaskScheduler.PostCallback(obj对象)
   在System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo方法,对象目标,对象[]参数,SignatureStruct和SIG,MethodAttributes methodAttributes,RuntimeType typeOwner)
   在System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo方法,对象目标,对象[]参数,签名的签名,MethodAttributes methodAttributes,RuntimeType typeOwner)
   在System.Reflection.RuntimeMethodInfo.Invoke(obj对象,的BindingFlags invokeAttr,粘结剂粘合,对象[]参数,CultureInfo的文化,布尔skipVisibilityChecks)
   在System.Delegate.DynamicInvokeImpl(对象[]参数)
   在System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry TME)
   在System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(obj对象)
   在System.Threading.ExecutionContext.runTry code(用户数据对象)
   在System.Runtime.CompilerServices.RuntimeHelpers.Execute codeWithGuaranteedCleanup(试行code code,清理code撤销code,对象用户数据)
   在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 TME)
   在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,IntPtr的WPARAM,LPARAM的IntPtr)
   在System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG与MSG)
   在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)
   在MyApp.Framework.SharedUI.ApplicationBase.InternalStart()在d:\\来源\\ S2 \\框架\\来源\\ UI \\ SharedUI \\ ApplicationBase.cs:190线
   在MyApp.Framework.SharedUI.ApplicationBase.Start()在d:\\来源\\ S2 \\框架\\来源\\ UI \\ SharedUI \\ ApplicationBase.cs:118线
   在MyApp.App1.WinUI.HDA.Main()在d:\\来源\\ S2 \\程序App1的\\ Sources \\ WinUI \\ HDA.cs:行63


解决方案

狡猾,我遇到了完全相同的行为时使用WPF,WCF和TPL的混合物。主线程的当前的SynchronizationContext将在少数情况下成为空。

  VAR背景= SynchronizationContext.Current;//如果上下文为null,一个异常
//当前的SynchronizationContext可能不被用作的TaskScheduler。
//将被抛出
TaskScheduler.FromCurrentSynchronizationContext();

据<一个href=\"http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/629d5524-c8db-466f-bc27-0ced11b441ba\">this帖子在MSDN论坛上,这是4.0的TPL确认的错误。的同事,被在4.5运行,并没有看到此行为。

我们通过使用FromCurrentSynchronizationContext主线程静态单创建的TaskScheduler,然后创建延续时总是引用任务调度解决了这个。例如:

 工作任务= Task.Factory.StartNew(()=&GT;
  {
    //东西
  }
).ContinueWith(T =&GT;
  {
    // UI的东西
  },TheSingleton.Current.UiTaskScheduler);

这避免了在TPL问题上的.NET 4.0。

更新
如果你已经安装了.NET开发机器上4.5,你不会看到即使你的目标4.0框架这一问题。谁只安装了4.0的用户还是会受到影响。

I have a problem in my application: At some point, the SynchronizationContext.Current becomes null for the main thread. I'm unable to reproduce the same problem in an isolated project. My real project is complex; it mixes Windows Forms and WPF and calls WCF Web Services. As far as I know, those are all systems that may interact with the SynchronizationContext.

This is the code from my isolated project. My real app does something that resembles that. However, in my real app the SynchronizationContext.Current is null on the main thread when the continuation task is executed.

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());
}

What could cause the SynchronizationContext.Current of the main thread to become null?

Edit:

@Hans asked for the stack trace. Here it is:


   at MyApp.Framework.UI.Commands.AsyncCommand.HandleTaskError(Task task) in d:\sources\s2\Framework\Sources\UI\Commands\AsyncCommand.cs:line 157
   at System.Threading.Tasks.Task.c__DisplayClassb.b__a(Object obj)
   at System.Threading.Tasks.Task.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()
   at System.Threading.Tasks.Task.ExecutionContextCallback(Object obj)
   at System.Threading.ExecutionContext.runTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot)
   at System.Threading.Tasks.Task.ExecuteEntry(Boolean bPreventDoubleExecution)
   at System.Threading.Tasks.SynchronizationContextTaskScheduler.PostCallback(Object obj)
   at System.RuntimeMethodHandle._InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, SignatureStruct& sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
   at System.RuntimeMethodHandle.InvokeMethodFast(IRuntimeMethodInfo method, Object target, Object[] arguments, Signature sig, MethodAttributes methodAttributes, RuntimeType typeOwner)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture, Boolean skipVisibilityChecks)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at System.Windows.Forms.Control.InvokeMarshaledCallbackDo(ThreadMethodEntry tme)
   at System.Windows.Forms.Control.InvokeMarshaledCallbackHelper(Object obj)
   at System.Threading.ExecutionContext.runTryCode(Object userData)
   at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode code, CleanupCode backoutCode, Object userData)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean ignoreSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Windows.Forms.Control.InvokeMarshaledCallback(ThreadMethodEntry tme)
   at System.Windows.Forms.Control.InvokeMarshaledCallbacks()
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
   at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
   at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
   at System.Windows.Forms.Application.Run(Form mainForm)
   at MyApp.Framework.SharedUI.ApplicationBase.InternalStart() in d:\sources\s2\Framework\Sources\UI\SharedUI\ApplicationBase.cs:line 190
   at MyApp.Framework.SharedUI.ApplicationBase.Start() in d:\sources\s2\Framework\Sources\UI\SharedUI\ApplicationBase.cs:line 118
   at MyApp.App1.WinUI.HDA.Main() in d:\sources\s2\App1\Sources\WinUI\HDA.cs:line 63

解决方案

Sly, I have run into the exact same behavior when a mixture of WPF, WCF, and TPL is used. The Main thread's current SynchronizationContext will become null in a few situations.

var context = SynchronizationContext.Current;

// if context is null, an exception of
// The current SynchronizationContext may not be used as a TaskScheduler.
// will be thrown
TaskScheduler.FromCurrentSynchronizationContext();

According to this post on the msdn forums, this is a confirmed bug in the TPL in 4.0. A coworker is running on 4.5 and does not see this behavior.

We solved this by creating a TaskScheduler in a static singleton with the main thread using FromCurrentSynchronizationContext and then always reference that task scheduler when creating continuations. For example

Task task = Task.Factory.StartNew(() =>
  {
    // something
  }
).ContinueWith(t =>
  {
    // ui stuff
  }, TheSingleton.Current.UiTaskScheduler);

This avoids the issue in the TPL on .net 4.0.

Update If you have .net 4.5 installed on your development machine, you will not see this issue even if you are targeting the 4.0 framework. Your users who only have 4.0 installed will still be affected.

这篇关于主线程的SynchronizationContext.Current如何在成为空Windows窗体应用程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆