原文地址:https://msdn.microsoft.com/magazine/gg598924.aspx
首先, 要了解到底什么是抽象上下文.
.NET 实现的抽象上下文可以给我们一个大概的印象. 在 mscorlib.dll 库中, System.Threading.SynchronizationContext 类是 .NET 提供的实现.
它提供了一个用于在不同的同步模式之间传递抽象上下文的功能. 这个类有个无参构造函数, 静态的属性表示当前的线程的同步上下文 Ccurrent. 有个 CreateCopy 方法.
IsWaitNotificationRequired() 方法确定当前对象是否需要等待线程通知. 两个虚方法 OperationCompleted OperationStarted 用来响应操作完成的动作.
Post 和 Send 方法用来给别的上下文传递异步信息. 静态方法 SetSynchronizationContext 用来设置当前的同步上下文对象. Wait 方法等待操作句柄收到通知.
今天开发遇到一个问题,stack overflow上有很简单的解决办法,但是我同事发现用那个解决办法有可能导致ui操作无法在ui线程上执行。
具体问题如下:
1. TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();
//TaskScheduler scheduler = TaskScheduler.Default;
2. SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
3. Task.Factory.StartNew(action).ContinueWith(result, scheduler);
scheduler是干嘛的? 可以不要吗
FromCurrentSynchronizationContext报错,察看当前context: System.Threading.SynchronizationContext.current 是第三方的Context
导致报错,can't be used as a scheduler
MSDN 上有篇文章
Parallel Computing - It's All About the SynchronizationContext
恰好是关于这个主题的,摘抄重点如下:ISynchronizeInvoke --> SynchronizationContext
ISynchronizeInvoke: 1. determining if synchronization was necessary
2. queue uow from one thread to another
SynchonizationContext: 1. queue uow to a context
2. no way to determining if synchronization is necessary
3. keeps count of outstanding asynchronous operations
Thread: 1. have a "current" context
2. its context is not necessarily unique
3. it's possible to change thrad's current context
Single UI threads: all delegates queued to them are executed one at a time by a specific UI thread in the order they were queued.
WindowsFormsSynchronizationContext
DispatcherSynchronizationContext
Default(ThreadPool)SynchronizationContext: if current context is null, then it has a default context. It's also implicitly applied to child threads
unless the child thread sets its own context.Thus, UI applications usually have two synchronization contexts: the UI SynchronizationContext covering the UI thread, and the default SynchronizationContext covering the ThreadPool threads
https://i-msdn.sec.s-msft.com/dynimg/IC468121.jpg
https://i-msdn.sec.s-msft.com/dynimg/IC468122.jpg
BackgroundWorkers do not have to run in UI Context!!!
SynchronizationContext provides a means for writing components that may work within many different frameworks. BackgroundWorker and WebClient are two examples that are equally at home in Windows Forms, WPF, Silverlight, console and ASP.NET apps.
Not all SynchronizationContext guarantee the order of delegate execution or synchronization of delegates. UI-based context do satisfy these conditions.
it’s best to not assume that any context instance will run on any specific thread
event-based asynchronous pattern VS task-based asynchronous pattern
when re-entrancy is desired, such as a client invoking a server method that invokes a client callback.
Task Parallel Library: TaskScheduler.FromCurrentSynchronizationContext and CancellationToken.Register
default TaskScheduler works like default context.
Figure 5 Progress Reporting with UI Updates
private void button1_Click(object sender, EventArgs e)
{
// This TaskScheduler captures SynchronizationContext.Current.
TaskScheduler taskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
// Start a new task (this uses the default TaskScheduler,
// so it will run on a ThreadPool thread).
Task.Factory.StartNew(() =>
{
// We are running on a ThreadPool thread here.
; // Do some work.
// Report progress to the UI.
Task reportProgressTask = Task.Factory.StartNew(() =>
{
// We are running on the UI thread here.
; // Update the UI with our progress.
},
CancellationToken.None,
TaskCreationOptions.None,
taskScheduler);
reportProgressTask.Wait();
; // Do more work.
});
}
Figure 4 Summary ofSynchronizationContext Implementations
| Specific Thread Used to Execute Delegates | Exclusive (Delegates Execute One at a Time) | Ordered (Delegates Execute in Queue Order) | Send May Invoke Delegate Directly | Post May Invoke Delegate Directly |
Windows Forms | Yes | Yes | Yes | If called from UI thread | Never |
WPF/Silverlight | Yes | Yes | Yes | If called from UI thread | Never |
Default | No | No | No | Always | Never |
ASP.NET | No | Yes | No | Always | Always |