【C#】【Thread】SynchronizationContext線程間同步

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

 

參考文章:http://blog.csdn.net/iloli/article/details/16859605

相關文章
相關標籤/搜索