在具有同步上下文的同一UI线程中完成操作

时间:2014-10-16 12:14:28

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

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

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

对于关闭操作,我使用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)是从另一个线程调用的,但Progress类型的_currentTask使用UI线程中捕获的上下文,但始终从UI线程以外的其他线程调用OnCompleted 。为什么?它必须在同一个环境中。

更新1:

System.Threading.SynchronizationContex System.Windows.Form.WindowsFormsSynchronizationContext System.Windows.Threading.DispatcherSynchronizationContext

1 个答案:

答案 0 :(得分:0)

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中创建了新的后台线程。它解决了这个问题。