【问题标题】:Complete operation in the same UI thread with synchronization context在具有同步上下文的同一 UI 线程中完成操作
【发布时间】:2017-02-22 20:59:55
【问题描述】:

从 UI (thread1) 我想创建一个进度 UI(thread2)。 Progress UI 在 thread3 中创建一个任务并等待其完成。

任务(thread3)完成并调用关闭进度UI,必须在thread2中执行。

对于关闭操作,我使用 AsyncOperationManager 来捕获 thread2 的上下文,然后从 thread4 执行 POST 方法。

但关闭总是从另一个线程发生。

以下所有代码均来自 ProgressWindows 类。

_currentTask = new Progress<double>(Close); // I call this in progress UI constructor.

// This is invoked in constructor of Progress class which is used inside ProgressWindow.
_asyncOperation = AsyncOperationManager.CreateOperation(null);

public static void Run2(Action action) 
{ 
    Debug.WriteLine(":: Run2 in thread: {0}", Thread.CurrentThread.ManagedThreadId); 

    var th = new Thread(_ => 
    { 
        Debug.WriteLine(":: StartNew in thread: {0}", Thread.CurrentThread.ManagedThreadId); 
        var progress = new ProgressWindow(); 
        progress.Run(action); 
    }); 

    th.SetApartmentState(ApartmentState.STA); 
    th.Start(); 
} 


 public void Run(Action action) 
 { 
    Debug.WriteLine(":: Run in thread: {0}", Thread.CurrentThread.ManagedThreadId); 

    SetupProgressBar(); 
    RunTask(action); 

    ShowDialog(); 
} 

private void RunTask(Action action) 
{ 
    Task.Factory.StartNew(action).ContinueWith(_ => _currentTask.OnCompleted(null)); 
} 

private void Close(object state) 
{ 
    Debug.WriteLine(":: Close in thread: {0}", Thread.CurrentThread.ManagedThreadId); 

    Hide(); 
    Close(); 
} 

问题是:

private void RunTask(Action action) 
{ 
    Task.Factory.StartNew(action).ContinueWith(_ => _currentTask.OnCompleted(null)); 
} 

你看,_currentTask.OnCompleted(null) 是从另一个线程调用的,但 _currentTaskof 类型的 Progress 使用在 UI 线程中捕获的上下文,但 OnCompleted 总是从 UI 线程以外的另一个线程调用。为什么?它必须在相同的上下文中。

更新 1:

混合 System.Threading.SynchronizationContextt 与 System.Windows.Form.WindowsFormsSynchronizationContextSystem.Windows.Threading.DispatcherSynchronizationContext

【问题讨论】:

  • 您正在从后台线程调用ContinueWith。你为什么认为它会将它编组到 UI 线程?
  • 因为在 ProgressWindow 的范围内我创建了 Progress,我在其中使用 AsyncOperationManager.CreateOperation 创建了 asyncOperation。我用 asyncOperation.Post 调用 OnCompleted。当然,这是相同的 UI 上下文......我想是的。
  • 使用 Dispatcher.BeginInvoke 解决了所有问题,但我想知道为什么 SynchronizationContext 在这里会被忽略?
  • 不确定,不熟悉AsyncOperationManager

标签: c# multithreading synchronization task-parallel-library


【解决方案1】:

Synchronization context in asynchronous WCF per call service

Force WCF to use one thread

AsyncOperationManager 的工作方式因调用 AsyncOperationManager.CreateOperation 的上下文而异。 根据上下文,AsyncOperationManager.CreateOperation 可能会创建三个上下文:

System.Threading.SynchronizationContext System.Windows.Form.WindowsFormsSynchronizationContext System.Windows.Threading.DispatcherSynchronizationContext

就我而言,当我在 ShowDialog 之前捕获上下文时,我捕获了线程同步上下文, 但是如果我在 OnLoad 事件中调用 AsyncOperationManager.CreateOperation,我会捕获 System.Windows.Form.WindowsFormsSynchronizationContext 或 DispatcherSynchronizationContext 取决于使用 WindowsForms 或 WPF。这就是错误的根源。

我会将其缩减为仅使用 Dispatcher.BeginInvoke。 但是为了将所有代码都保留在 Progress 中,我只是将 AsyncOperationManager.CreateOperation 并在 ProgressWindow UI 的 OnLoad 中创建了新的后台线程。它已经解决了这个问题。

【讨论】:

    猜你喜欢
    • 2015-06-09
    • 1970-01-01
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多