20

나는 윈폼 응용 프로그램에서 다음 문제를 추적하기 위해 노력했습니다 null의 경우 주 스레드 (나는 현재 동기화 컨텍스트가 System.Windows.Forms.WindowsFormsSynchronizationContext 일 것으로 기대한다). 나는 계속에서 BackgroundWorker를 사용하려고 시도하고있는 BackgroundWorker가 해당 이벤트 RunWorkerCompletedProgressChanged의 현재에서 SynchronizationContext를 사용하기 때문에SynchronizationContext.Current 메인 UI에 계속에서 스레드

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를 시작하면 현재 SynchronizationContext가 null이므로 이벤트는 의도 한대로 주 UI 스레드에서 실행되지 않습니다.

내 질문 :
는 Microsoft의 코드에서 버그, 아니면 어디 선가 실수를했다?

추가 정보 :

  • 내가 닷넷 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의 버그라고 가정합니다. 또한, 나는이 게시물 같은 문제를 참조하는 같은데요 : 불행

합니다. 이제 해결 방법을 고려해야합니다.

편집 : 닷넷 소스에 디버깅에서
, 내가 문제가 재현 할 때 조금 더 잘 이해할 수있다. 우리가 RunInternal를 호출하는 "다른"절에 들어갈 때

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

문제는 재생하기 : 여기 ExecutionContext.cs에서 일부 관련 코드입니다.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이기 때문에 이것이 참이었습니다. 여기에 코드입니다 :

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

버그 마이크로 소프트 담당자 중 한 명이 ".NetFramework 4.0에서이 문제를 재현 할 수 있었고 다음 릴리스에서 수정되었다는 것을 확인했습니다."라고 말한 후입니다. 이것이 수정되었는지 알고 싶습니다. 4.0 또는 단지 4.5 인치 – jpierson

관련 문제