同步上下文的作用,官方解释是:
提供在各种同步模型中传播同步上下文的基本功能。同步上下文的工作就是确保调用在正确的线程上执行。
官方解释抽象难以理解,摘抄了网上了其它的解释如下:
在99.9%的使用场景中,SynchronizationContext仅仅被当作一个提供虚(virtual)Post方法的类, 该方法可以接收一个委托,然后异步执行它。虽 然SynchronizationContext还有许多其他的虚成员, 但是很少使用它们,而且和我们今天的内容无关,就不说了。 Post方法的基础实现就仅仅是调用一下ThreadPool.QueueUserWorkItem, 将接收的委托加入线程池队列去异步执行。 另外,派生类可以选择重写(override)Post方法,让委托在更加合适的位置和时间去执行。 例如,WinForm有一个派生自SynchronizationContext的类,重写了Post方法, 内部执行Control.BeginInvoke, 这样,调用该Post方法就会在该控件的UI线程上执行接收的委托。 WinForm依赖Win32的消息处理机制,并在UI线程上运行“消息循环”, 该线程就是简单的等待新消息到达,然后去处理。 这些消息可能是鼠标移动和点击、键盘输入、系统事件、可供调用的委托等。 所以,只需要将委托传递给SynchronizationContext实例的Post方法,就可以在控件的UI线程中执行。 和WinForm一样,WPF也有一个派生自SynchronizationContext的类,重写了Post方法, 通过Dispatcher.BeginInvoke将接收的委托封送到UI线程。 与WinForm通过控件管理不同的是,WPF是由Dispatcher管理的。 Windows运行时(WinRT)也不例外,它有一个派生自SynchronizationContext的类, 重写了Post方法,通过CoreDispatcher将接收的委托排队送到UI线程。
与抽象的优点一样:SynchronizationContext它提供了一个API, 可用于将委托排队进行处理,无需了解该实现的细节,这是实现者所期望的。 所以,如果我正在编写一个库,想要停下来做一些工作,然后将委托排队送回“原始上下文”继续执行, 那么我只需要获取他们的SynchronizationContext,存下来。 当完成工作后,在该上下文上调用Post去传递我想要调用的委托即可。 我不需在WinForm中知道要获取一个控件并调用BeginInvoke, 不需要在WPF中知道要对Dispatcher进行BeginInvoke, 也不需要在xunit中知道要以某种方式获取其上下文并排队, 我只需要获取当前的SynchronizationContext并在以后使用它就可以了。
SynchronizationContext类的方法原型如下:
namespace System.Threading
{
//
// 摘要:
// 提供在各种同步模型中传播同步上下文的基本功能。
public class SynchronizationContext
{
//
// 摘要:
// 创建 System.Threading.SynchronizationContext 类的新实例。
public SynchronizationContext();
//
// 摘要:
// 获取当前线程的同步上下文。
//
// 返回结果:
// 一个 System.Threading.SynchronizationContext 对象,它表示当前同步上下文。
public static SynchronizationContext Current { get; }
//
// 摘要:
// 设置当前同步上下文。
//
// 参数:
// syncContext:
// 要设置的 System.Threading.SynchronizationContext 对象。
[SecurityCritical]
[TargetedPatchingOptOut("Performance critical to inline across NGen image boundaries")]
public static void SetSynchronizationContext(SynchronizationContext syncContext);
//
// 摘要:
// 用于等待指定数组中的任一元素或所有元素接收信号的 Helper 函数。
//
// 参数:
// waitHandles:
// 一个类型为 System.IntPtr 的数组,其中包含本机操作系统句柄。
//
// waitAll:
// 若等待所有句柄,则为 true;若等待任一句柄,则为 false。
//
// millisecondsTimeout:
// 等待的毫秒数,或为 System.Threading.Timeout.Infinite (-1),表示无限期等待。
//
// 返回结果:
// 满足等待的对象的数组索引。
[CLSCompliant(false)]
[PrePrepareMethod]
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.MayFail)]
[SecurityCritical]
protected static int WaitHelper(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout);
//
// 摘要:
// 当在派生类中重写时,创建同步上下文的一个副本。
//
// 返回结果:
// 一个新的 System.Threading.SynchronizationContext 对象。
public virtual SynchronizationContext CreateCopy();
//
// 摘要:
// 确定是否需要等待通知。
//
// 返回结果:
// 如果需要等待通知,则为 true;否则为 false。
public bool IsWaitNotificationRequired();
//
// 摘要:
// 当在派生类中重写时,响应操作已完成的通知。
public virtual void OperationCompleted();
//
// 摘要:
// 当在派生类中重写时,响应操作已开始的通知。
public virtual void OperationStarted();
//
// 摘要:
// 当在派生类中重写时,将异步消息调度到一个同步上下文。
//
// 参数:
// d:
// 要调用的 System.Threading.SendOrPostCallback 委托。
//
// state:
// 传递给委托的对象。
public virtual void Post(SendOrPostCallback d, object state);
//
// 摘要:
// 当在派生类中重写时,将一个同步消息调度到一个同步上下文。
//
// 参数:
// d:
// 要调用的 System.Threading.SendOrPostCallback 委托。
//
// state:
// 传递给委托的对象。
//
// 异常:
// T:System.NotSupportedException:
// 在 Windows Store 应用程序中调用的方法。用于 Windows Store 应用程序的 System.Threading.SynchronizationContext
// 的实现应用不支持 System.Threading.SynchronizationContext.Send(System.Threading.SendOrPostCallback,System.Object)
// 方法。
public virtual void Send(SendOrPostCallback d, object state);
//
// 摘要:
// 等待指定数组中的任一元素或所有元素接收信号。
//
// 参数:
// waitHandles:
// 一个类型为 System.IntPtr 的数组,其中包含本机操作系统句柄。
//
// waitAll:
// 若等待所有句柄,则为 true;若等待任一句柄,则为 false。
//
// millisecondsTimeout:
// 等待的毫秒数,或为 System.Threading.Timeout.Infinite (-1),表示无限期等待。
//
// 返回结果:
// 满足等待的对象的数组索引。
//
// 异常:
// T:System.ArgumentNullException:
// waitHandles 为 null。
[CLSCompliant(false)]
[PrePrepareMethod]
[SecurityCritical]
public virtual int Wait(IntPtr[] waitHandles, bool waitAll, int millisecondsTimeout);
//
// 摘要:
// 设置指示需要等待通知的通知,并准备回调方法以使其在发生等待时可以更可靠地被调用。
[SecuritySafeCritical]
protected void SetWaitNotificationRequired();
}
}来张方法的缩略图:

使用上下文的这些方法,最基本的应用就是用来跨线程更新UI。
WinFroms和WPF都继承了SynchronizationContext,使同步上下文能够在UI线程或者Dispatcher线程上正确执行
System.Windows.Forms. WindowsFormsSynchronizationContext System.Windows.Threading. DispatcherSynchronizationContext
勇哥写了段演示代码,有详细注释:
其中第三项inoke,是我们之前很熟悉的异步调用。
最后一项Task的,是用到.net 4.0的Task的TaskScheduler(任务调度),属于新特性。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WindowsFormsApplication6
{
public partial class Form1 : Form
{
//提供在各种同步模型中传播同步上下文的基本功能。同步上下文的工作就是确保调用在正确的线程上执行。
//Current 获取当前同步上下文
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
var context = SynchronizationContext.Current;
SendOrPostCallback callback = o =>
{
//TODO:
label1.Text = "Hello Send";
};
//Send 一个同步消息调度到一个同步上下文。
//send调用后会阻塞直到调用完成。
context.Send(callback, null);
}
private void button2_Click(object sender, EventArgs e)
{
var context = SynchronizationContext.Current;
SendOrPostCallback callback = o =>
{
//TODO:
label2.Text = "Hello Post";
};
//Post 将异步消息调度到一个同步上下文。
//和send的调用方法一样,不过Post会启动一个线程来调用,不会阻塞当前线程。
context.Post(callback, null);
}
private void button3_Click(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(BackgroudRun);
}
private void BackgroudRun(object state)
{
this.Invoke(new Action(() =>
{
label3.Text = "Hello Invoke";
}));
}
private void button4_Click(object sender, EventArgs e)
{
var context = SynchronizationContext.Current; //获取同步上下文
Debug.Assert(context != null);
ThreadPool.QueueUserWorkItem(BackgroudRun2, context);
}
private void BackgroudRun2(object state)
{
var context = state as SynchronizationContext; //传入的同步上下文
Debug.Assert(context != null);
SendOrPostCallback callback = o =>
{
label4.Text = "Hello SynchronizationContext";
};
context.Send(callback, null); //调用
}
private void button5_Click(object sender, EventArgs e)
{
// 创建一个SynchronizationContext 关联的 TaskScheduler
var scheduler = TaskScheduler.FromCurrentSynchronizationContext();
Task.Factory.StartNew(() => label5.Text = "Hello TaskScheduler", CancellationToken.None,
TaskCreationOptions.None, scheduler);
}
}
}另载一篇关于Application.Current.Dispatcher跟SynchronizationContext啥子不同的问答篇,涨一下知识。

---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!


少有人走的路



















