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"); }