SynchronizationContext在通訊中充當傳輸者的角色,實現功能就是一個線程和另外一個線程的通訊。
需要注意的是,不是每個線程都附加SynchronizationContext這個對象,只有UI線程是一直擁有的。故獲取SynchronizationContext也只能在UI線程上進行SynchronizationContext context = SynchronizationContext.Current;
那什么時候會用到呢?
在多線程操作時往往需要切回某個線程中去工作,等完成后再切回來。
如主UI線程中創建了一個子線程A。A中添加了委托事件。UI線程中向A線程的類注冊了事件,當A線程觸發事件時去修改UI上的屬性如TEXT。
這個時候往往要在UI線程向子線程注冊的事件方法中使用控件的invoke方法才能訪問UI線程中的控件,因為這些注冊的事件(委托)方法代碼雖然看似寫在UI線程的Form類中,但實際上是注冊在了子線程A的事件中,它們是會被子線程A觸發事件時在子線程內部執行的。這樣,我們不得不在主UI線程的類的注冊事件方法中通過控件的Invoke方法才能訪問控件,這樣做十分麻煩。我們想和系統的控件事件一樣,直接在注冊的事件方法中訪問控件。那么這個時候就可以用SynchronizationContext了。
SynchronizationContext.Send(SendOrPostCallback d,object state);
SynchronizationContext.Post(SendOrPostCallback d,object state);
d 為一個沒有返回值,並且具有一個Object類型傳入參數的委托(SendOrPostCallback );
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"); }
參考文章:http://blog.csdn.net/iloli/article/details/16859605