原文地址:https://msdn.microsoft.com/magazine/gg598924.aspx
今天开发遇到一个问题,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 上有篇文章
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 |