SynchronizationContext在通信中充当传输者的角色,实现功能就是一个线程和另一个线程的通信。多线程
须要注意的是,不是每一个线程都附加SynchronizationContext这个对象,只有UI线程是一直拥有的。故获取SynchronizationContext也只能在UI线程上进行SynchronizationContext context = SynchronizationContext.Current;异步
那何时会用到呢?spa
在多线程操做时每每须要切回某个线程中去工做,等完成后再切回来。.net
如主UI线程中建立了一个子线程A。A中添加了委托事件。UI线程中向A线程的类注册了事件,当A线程触发事件时去修改UI上的属性如TEXT。线程
这个时候每每要在UI线程向子线程注册的事件方法中使用控件的invoke方法才能访问UI线程中的控件,由于这些注册的事件(委托)方法代码虽然看似写在UI线程的Form类中,但其实是注册在了子线程A的事件中,它们是会被子线程A触发事件时在子线程内部执行的。这样,咱们不得不在主UI线程的类的注册事件方法中经过控件的Invoke方法才能访问控件,这样作十分麻烦。咱们想和系统的控件事件同样,直接在注册的事件方法中访问控件。那么这个时候就能够用SynchronizationContext了。code
SynchronizationContext.Send(SendOrPostCallback d,object state);orm
SynchronizationContext.Post(SendOrPostCallback d,object state);对象
d 为一个没有返回值,而且具备一个Object类型传入参数的委托(SendOrPostCallback );blog
state 为执行这个委托时的参数(object);事件
注意:
SynchronizationContext的对象不是全部线程都被附加的,只有UI主线程会被附加。
对于UI线程来讲,是如何将SynchronizationContext这个对象附加到线程上的呢?
在Form1 form = new Form1()以前,SynchronizationContext对象是为空,而当实例化Form1窗体后,SynchronizationContext对象就被附加到这个线程上了。
因此能够得出答案了:当Control对象被建立的同时,SynchronizationContext对象也会被建立并附加到线程上。因此在使用时,必定要等窗体InitializeComponent(); 这个完成后 它才能获得一个不是NULL的对象.
那么SynchronizationContext的Send()和Post()二个方法有什么区别呢?
Send() 是简单的在当前线程上去调用委托来实现(同步调用)。也就是在子线程上直接调用UI线程执行,等UI线程执行完成后子线程才继续执行。
Post() 是在线程池上去调用委托来实现(异步调用)。这是子线程会从线程池中找一个线程去调UI线程,子线程不等待UI线程的完成而直接执行本身下面的代码。
例子:
/// <summary> /// 这里须要在主线程里定义, /// 并在主线程得到context = SynchronizationContext.Current /// </summary> private SynchronizationContext context; /// <summary> /// 窗体加载 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void Form1_Load(object sender, EventArgs e) { //此处就是以前提的在主线程得到SynchronizationContext context = SynchronizationContext.Current; //以后能够开线程了 Thread thread = new Thread(new ThreadStart(Start)); thread.IsBackground = true; thread.Start(); } /// <summary> /// 线程操做 /// </summary> private void Start() { for(int i=0;i<100;++i) { //这边便可正常调用主界面的控件了 context.Send(operation, i);//正确 //按原先直接应用,由于使用到控件会报错 operation(i);//报错 Thread.Sleep(100); } } /// <summary> /// 线程操做 /// </summary> /// <param name="obj"></param> private void operation(object obj) { textBox1.AppendText(obj.ToString() + "\r\n"); }