C#學習筆記之invoke與BeginInvoke

C#學習筆記之 invoke與BeginInvoke

​ 前段時間在寫C#的上位機,用到invoke和BeginInvoke。前面對這兩個的用法和原理比較模糊,這幾天參考了網上的一些資料,整理如下筆記。

1.1 invoke與BeginInvoke介紹

invoke與BeginInvoke的兩種使用情況:
1.control中的invoke、BeginInvoke
2.delegrate中的invoke、BeginInvoke
這兩種情況是不同的,這裏主要介紹第一種。dotNET中對invoke和BeginInvoke的官方定義如下:
control.invoke(參數delegate)方法:在擁有此控件的基礎窗口句柄的線程上執行指定的委託
control.BeginInvoke(參數delegate)方法:在創建此控件的基礎窗口句柄的線程上異步執行指定的委託
其中Control中的invoke和BeginInvoke的參數爲delegate,委託的方法是在Control的線程上執行的,即UI線程。由定義我們可以知道invoke表示同步、Begininvoke表示異步

下面做一個測試:

新建一個UI工程,界面如下圖1
測試界面

1.2 invoke分析:

invoke代段碼如下:

        private void invoke_btn_Click(object sender, EventArgs e)
        {
       	    //主線程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "AAA");
            invokeThread = new Thread(new ThreadStart(StartMethod));
            invokeThread.Start();
            string ch = string.Empty;
            for(int ss = 0; ss < 3; ss++)
            {
                Thread.Sleep(1000);
                ch = ch + "B";
            }
            //主線程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + ch); 
        }

        private void StartMethod()
        {
            //子線程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "CCC");
            //提交到主線程
            invoke_btn.Invoke(new InvokeDelegate(invokeMethod));
            //子線程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "DDD");

        }

        private void invokeMethod()
        {
            //主線程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "EEE");
            
        }

​ 測試結果:雙擊運行exe,單擊invoke,程序運行的界面:1AAA->3CCC和1BBB->1EEE->3DDD。(Debug模式下的HashCode可能不一樣,但是運行的順序是一樣的)
​ 結果分析:單擊invoke按鈕後,執行invoke_btn_Click函數,主線程運行AAA,然後BBB和子線程CCC同時執行(這裏用循環+延時,顯示更加清楚),接着通過invoke來將invokeMethod方法提交給主線程,然後子線程等待主線程執行完畢(即等待EEE執行完成),最後執行子線程的DDD。

1.3 BeginInvoke分析:

BeginInvoke代段碼如下:

		private void bginvoke_btn_Click(object sender, EventArgs e)
		{
		    //主線程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "AAA");
            bginvokeThread = new Thread(new ThreadStart(bgStartMethod));
            bginvokeThread.Start();
            string ch = string.Empty;
            for (int ss = 0; ss < 3; ss++)      
            {
                Thread.Sleep(1000);
                ch = ch + "B";
            }
            //主線程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + ch);
        }

        private void bgStartMethod()
        {
            //子線程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "CCC");
            //提交給主線程
            bginvoke_btn.BeginInvoke(new InvokeDelegate(bginvokeMethod));
            //子線程
            MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "DDD");
            

        }

        private void bginvokeMethod()
        {	
        //主線程
         MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "EEE");
        }
    

​ 測試結果:雙擊運行exe,單擊BeginInvoke,程序運行的界面:1AAA->3CCC和1BBB->1EEE和3DDD。(Debug模式下的HashCode可能不一樣,但是運行的順序是一樣的)
結果分析:單擊BeginInvoke按鈕後,執行bginvoke_btn_Click函數,主線程運行AAA,然後BBB和子線程CCC同時執行,然後通過BeginInvoke來將bginvokeMethod方法提交給主線程,接着主線程執行EEE(主線程自己的任務完成),同時子線程繼續執行DDD。

1.4對比分析

​ 通過上述兩個測試可以發現:invoke和BeginInvoke提交的委託方法都是在主線程中執行的。但是invoke所提交的委託方法是(EEE)執行完畢後,才繼續執行的DDD;而BeginInvoke提交的委託方法後,子線程可以繼續執行DDD,不需要等待EEE執行完畢。因此在兩者的使用方面是不同的,當後臺線程在更新一個UI控件的狀態後不需要等待,而是繼續往下執行,此時宜用BeginInvoke來進行處理,如一邊接收數據,將數據存入隊列,一邊對數據隊列進行文本,曲線的更新;當後臺線程需要操作UI控件,並且需要等待該操作執行完畢才能繼續往下執行,此時宜用invoke來進行處理,如必須接收一幀立即處理一幀數據。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章