20

に継続してnullである:
SynchronizationContext.Currentは、タスクの継続でヌルである(すなわち.ContinueWith)上で実行されていますメインスレッド(私は現在の同期コンテキストがSystem.Windows.Forms.WindowsFormsSynchronizationContextであることを期待しています)。ここでSynchronizationContext.Currentは、私はWinformsのアプリケーションで次の問題を追跡しようとしてきたメインUIスレッド

は、問題を実証Winformsのコードです:

using System; 
using System.Threading; 
using System.Threading.Tasks; 
using System.Windows.Forms; 

namespace WindowsFormsApplication1 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
      TaskScheduler ts = TaskScheduler.FromCurrentSynchronizationContext(); // Get the UI task scheduler 

      // This line is required to see the issue (Removing this causes the problem to go away), since it changes the codeflow in 
      // \SymbolCache\src\source\.NET\4\DEVDIV_TFS\Dev10\Releases\RTMRel\ndp\clr\src\BCL\System\Threading\ExecutionContext.cs\1305376\ExecutionContext.cs 
      // at line 435 
      System.Diagnostics.Trace.CorrelationManager.StartLogicalOperation("LogicalOperation"); 

      var task = Task.Factory.StartNew(() => { }); 
      var cont = task.ContinueWith(MyContinueWith, CancellationToken.None, TaskContinuationOptions.None, ts); 

      System.Diagnostics.Trace.CorrelationManager.StopLogicalOperation(); 
     } 

     void MyContinueWith(Task t) 
     { 
      if (SynchronizationContext.Current == null) // The current SynchronizationContext shouldn't be null here, but it is. 
       MessageBox.Show("SynchronizationContext.Current is null"); 
     } 
    } 
} 

私は続きからBackgroundWorkerを使用しようとするので、これは私にとって問題であり、BackgroundWorkerのは、そのイベントRunWorkerCompletedProgressChangedの現在のSynchronizationContextを使用します。 BackgroundWorkerを起動すると、現在のSynchronizationContextがnullなので、イベントは主UIスレッドで実行されません。

私の質問:
が、これはMicrosoftのコードのバグですか、私はどこかでミスを犯してきましたか?

追加情報:

  • 私は.NET 4.0を使用していますが、私はどんなの両方のデバッグ/リリースでこれを再現することができ
  • (私はまだ.NET 4.5 RCでこれを試していません) x86/x64 /任意のCPU(x64マシン上)
  • これは一貫して再現します(誰かがそれを再現できない場合は興味があります)。
  • 私は、BackgroundWorkerのを使用してレガシーコードを持っている - ので、私は簡単に私がMyContinueWithのコードは、メインUIスレッド上で実行されていることを確認しましたBackgroundWorkerの
  • を使用していないに切り替えることはできません。
  • StartLogicalOperationコールが問題の原因となっている理由を正確にはわかりませんが、それは私のアプリケーションで絞り込んだものです。
+0

さて、あなたはそのリンクから診断を受けています。このWinformsアプリケーションにWPFまたはWCFコードを混在させていますか? –

+0

いいえ - Winformsのみ。 –

答えて

20

問題は.NET 4.5 RCで修正されています(テスト済みです)。だから私はそれが.NET 4.0のバグだと考えています。

残念だ: はまた、私はこれらの記事は、同じ問題を参照していることを推測しています。今私は回避策を検討する必要があります。

編集:
ネットソースにデバッグから、私は、問題が再現するだろうというときの少し良く理解しています。ここにExecutionContext.csからいくつかの関連するコードは次のとおりです。

 internal static void Run(ExecutionContext executionContext, ContextCallback callback, Object state, bool ignoreSyncCtx) 
     { 
      // ... Some code excluded here ... 

      ExecutionContext ec = Thread.CurrentThread.GetExecutionContextNoCreate(); 
      if ((ec == null || ec.IsDefaultFTContext(ignoreSyncCtx)) && 
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK 
       SecurityContext.CurrentlyInDefaultFTSecurityContext(ec) && 
#endif // #if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK 
       executionContext.IsDefaultFTContext(ignoreSyncCtx)) 
      { 
       callback(state); 
      } 
      else 
      { 
       if (executionContext == s_dummyDefaultEC) 
        executionContext = s_dummyDefaultEC.CreateCopy(); 
       RunInternal(executionContext, callback, state); 
      } 
     } 

我々はRunInternalを呼び出し、「他の」句に入る際にのみ問題が再現します。RunInternalが変化するものを、現在のSynchronizationContextの効果を持っているのExecutionContextを交換して終わるので、これは次のとおりです。ライン `executionContext.IsDefaultFTContext(ignoreSyncCtx))が返したため、

 // Get the current SynchronizationContext on the current thread 
     public static SynchronizationContext Current 
     { 
      get 
      { 
       SynchronizationContext context = null; 
       ExecutionContext ec = Thread.CurrentThread.GetExecutionContextNoCreate(); 
       if (ec != null) 
       { 
        context = ec.SynchronizationContext; 
       } 

       // ... Some code excluded ... 
       return context; 
      } 
     } 

だから、私の特定のケースのために、それはでした偽です。私にとって

 internal bool IsDefaultFTContext(bool ignoreSyncCtx) 
     { 
#if FEATURE_CAS_POLICY 
      if (_hostExecutionContext != null) 
       return false; 
#endif // FEATURE_CAS_POLICY 
#if FEATURE_SYNCHRONIZATIONCONTEXT 
      if (!ignoreSyncCtx && _syncContext != null) 
       return false; 
#endif // #if FEATURE_SYNCHRONIZATIONCONTEXT 
#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK 
      if (_securityContext != null && !_securityContext.IsDefaultFTSecurityContext()) 
       return false; 
#endif //#if FEATURE_IMPERSONATION || FEATURE_COMPRESSEDSTACK 
      if (_logicalCallContext != null && _logicalCallContext.HasInfo) 
       return false; 
      if (_illogicalCallContext != null && _illogicalCallContext.HasUserData) 
       return false; 
      return true; 
     } 

、原因_logicalCallContext.HasInfoにfalseを返していました本当だった:ここではそのコードです。そのコードは次のとおりです。

public bool HasInfo 
{ 
    [System.Security.SecurityCritical] // auto-generated 
    get 
    { 
     bool fInfo = false; 

     // Set the flag to true if there is either remoting data, or 
     // security data or user data 
     if(
      (m_RemotingData != null && m_RemotingData.HasInfo) || 
      (m_SecurityData != null && m_SecurityData.HasInfo) || 
      (m_HostContext != null) || 
      HasUserData 
     ) 
     { 
      fInfo = true; 
     } 

     return fInfo; 
    } 
} 

私にとっては、HasUserDataがtrueであったため、これはtrueを返していました。ここではそのコードです:

internal bool HasUserData 
    { 
     get { return ((m_Datastore != null) && (m_Datastore.Count > 0));} 
    } 

私にとっては、m_DataStoreが原因要約Diagnostics.Trace.CorrelationManager.StartLogicalOperation("LogicalOperation");

に私の呼び出しにその中のアイテムを持っているでしょう、あなたはバグが再現するために得ることができるいくつかの異なる方法があるように見えます。うまくいけば、この例は、他の人が同じバグに遭遇しているかどうかを判断するのに役立ちます。

+1

Microsoft PSSに連絡して、修正プログラムを入手できるかどうかを確認できます。 –

+3

私はここにバグレポートを提出しました:https://connect.microsoft.com/VisualStudio/feedback/details/755320/synchronizationcontext-current-is-null-in-continuation-on-the-main-ui-thread –

+0

あなたのバグMicrosoftの代理人の一人が「.NetFramework 4.0でこの問題を再現でき、次のリリースで修正されていることを確認した」と述べた後である。これが修正されているかどうかを知りたい4.0またはちょうど4.5インチ – jpierson