C#Delegate.Invoke、Delegate.BeginInvoke And Control.Invoke、Control.BeginInvoke


作者:EasonLeung

一、Delegate的Invoke、BeginInvoke

1、Delegate.Invoke (委托同步調用)

  a、委托的Invoke方法,在當前線程中執行委托。

  b、委托執行時阻塞當前線程,知道委托執行完畢,當前線程才繼續向下執行。

  c、委托的Invoke方法,類似方法的常規調用。

2、Delegate.BeginInvoke (委托異步調用)

  a、委托的BeginInvoke方法,在線程池分配的子線程中執行委托

  b、委托執行時不會阻塞主線程(調用委托的BeginInvoke線程),主線程繼續向下執行。

  c、委托執行時會阻塞子線程。

  d、委托結束時,如果有返回值,子線程講返回值傳遞給主線程;如果有回調函數,子線程將繼續執行回調函數。

3、Demo

  a、Delegate

 1         private void btn_General_Click(object sender, EventArgs e)
 2         {
 3             txt_Message.Text = "";
 4             txt_Message.Text += "主線程:"+ Thread.CurrentThread.ManagedThreadId + "---開始工作\r\n";
 5             //委托方法,在調用委托的線程中執行,本例中就是主線程(UI線程)。
 6             //執行一些耗時的操作,就會阻塞主線程(UI線程)
 7             //委托的普通調用就等於方法的直接調用,del();等價於SomeWork();
 8             del();
 9             //SomeWork();
10             txt_Message.Text += "\r\n主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始結束\r\n";
11         }

   b、Delegate.Invoke

1         private void btn_Main_Invoke_Click(object sender, EventArgs e)
2         {
3             txt_Message.Text = "";
4             txt_Message.Text += "主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始工作\r\n";
5             //委托的同步調用,其實就是等價於委托的普通調用。
6             del.Invoke();
7             txt_Message.Text += "\r\n主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始結束\r\n";
8         }
 1         private void btn_Sub_Invoke_Click(object sender, EventArgs e)
 2         {
 3             txt_Message.Text = "";
 4             txt_Message.Text += "主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始工作\r\n";
 5 
 6             //開啟新的線程執行委托,主線程(UI線程)繼續向下執行
 7             new Thread(() => {
 8                 txt_Message.Text += "\r\n----子線程:" + Thread.CurrentThread.ManagedThreadId + "---開始工作\r\n";
 9                 //委托在調用線程中執行,並阻塞調用線程,知道委托方法執行結束。
10                 del.Invoke();
11                 txt_Message.Text += "\r\n----子線程:" + Thread.CurrentThread.ManagedThreadId + "---開始結束\r\n";
12             }).Start();
13 
14             txt_Message.Text += "\r\n主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始結束\r\n";
15         }

  c、Delegate.BeginInvoke

 1         private void btn_Main_BeginInvoke_Click(object sender, EventArgs e)
 2         {
 3             txt_Message.Text = "";
 4             txt_Message.Text += "主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始工作\r\n";
 5             //委托異步調用
 6             //1、委托方法,在線程池中分配的子線程中執行。
 7             //2、主線程和子線程同時執行。
 8             //3、子線程結束之后,如果有返回值得話,將返回值傳遞給主線程。如果有回調函數的話,繼續在子線程中執行回調函數。
 9 
10             //有異常,控件不能在子線程中訪問修改。
11             //避免這類異常有兩種方法   
12             //1、手動關閉控件的跨線程安全檢查Control.CheckForIllegalCrossThreadCalls = false;(不建議使用)
13             //2、使用控件的Invoke方法。(推薦使用)
14             del.BeginInvoke(null,null);
15             txt_Message.Text += "\r\n主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始結束\r\n";
16         }
 1         private void btn_Sub_BeginInvoke_Click(object sender, EventArgs e)
 2         {
 3             txt_Message.Text = "";
 4             txt_Message.Text += "主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始工作\r\n";
 5 
 6             //開啟新的線程執行委托,主線程(UI線程)繼續向下執行
 7             new Thread(() =>
 8             {
 9                 txt_Message.Text += "\r\n----子線程:" + Thread.CurrentThread.ManagedThreadId + "---開始工作\r\n";
10                 //在線程池中分配的子線程中執行委托方法,調用委托的線程繼續向下執行。
11                 del.BeginInvoke(null, null); 
12                 txt_Message.Text += "\r\n----子線程:" + Thread.CurrentThread.ManagedThreadId + "---開始結束\r\n";
13             }).Start();
14 
15             txt_Message.Text += "\r\n主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始結束\r\n";
16         }

 




作者:EasonLeung

二、Control的Invoke、BeginInvoke

1、Control.Invoke (同步調用)  

  (1)在主線程(UI線程)中調用Control.Invoke

    a、在主線程(UI線程)中調用Control.Invoke,先執行Invoke的方法,再執行Invoke后面的代碼。

  (2)在子線程中調用Control.Invoke

    a、子線程中調用Control.Invoke,子線程將調用的方法封裝成消息,調用API的RegisterWindowMessage()向UI窗口發送消息。 主線程繼續向下執行,子線程處於阻塞狀態。

    b、當該消息被主線程執行完成后,子線程才能繼續往下執行。

2、Delegate.BeginInvoke (異步調用)

  (1)在主線程(UI線程)中調用Control.BeginInvoke

    a、在主線程(UI線程)中調用Control.BeginInvoke,將調用的方法封裝成消息,調用API的RegisterWindowMessage()向UI窗口發送消息。先執行Invoke后面的代碼,再執行Invoke的方法。

  (2)在子線程中調用Control.BeginInvoke

    a、子線程中調用Control.BeginInvoke,子線程將調用的方法封裝成消息,調用API的RegisterWindowMessage()向UI窗口發送消息。主線程繼續向下執行,子線程也繼續向下執行。

    b、最后由主線程執行Invoke的方法

3、Demo

  a、在主線程(UI線程)中調用Control.Invoke

 1         private void btn_Main_Invoke_Click(object sender, EventArgs e)
 2         {
 3             //執行順序:代碼A -> 代碼Invoke -> 代碼B
 4             //都是在主線程中執行
 5 
 6             txt_Message.Text = "";
 7             txt_Message.Text += "主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始工作\r\n";
 8             //代碼A
 9             this.txt_Message.Invoke(del);
10             //代碼B
11             txt_Message.Text += "\r\n主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始結束\r\n";
12         }

  b、在子線程中調用Control.Invoke

 1         private void btn_Sub_Invoke_Click(object sender, EventArgs e)
 2         {
 3             //執行順序:
 4             //1、代碼A(主線程執行)
 5             //2、代碼D(主線程執行) 和 代碼B(子線程執行) 並發執行
 6             //3、封裝消息,並在UI線程中注冊消息(子線程執行)
 7             //4、代碼Invoke(主線程執行)
 8             //5、代碼C(子線程執行)
 9 
10             txt_Message.Text = "";
11             txt_Message.Text += "主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始工作\r\n";
12             //代碼A
13             new Thread(() =>
14             {
15                 //代碼B
16                 int temp = 0;
17                 this.txt_Message.Invoke(del);
18                 //代碼C
19                 temp = 1;
20             }).Start();
21             //代碼D
22             txt_Message.Text += "\r\n主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始結束\r\n";
23         }

  c、在主線程(UI線程)中調用Control.BeginInvoke

 1         private void btn_Main_BeginInvoke_Click(object sender, EventArgs e)
 2         {
 3             //執行順序:代碼A -> 封裝消息,並在UI線程中注冊消息 -> 代碼B -> 代碼Invoke
 4             //都是在主線程中執行
 5 
 6             txt_Message.Text = "";
 7             txt_Message.Text += "主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始工作\r\n";
 8             //代碼A
 9             this.txt_Message.BeginInvoke(del);
10             //代碼B
11             txt_Message.Text += "\r\n主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始結束\r\n";
12         }

  c、在子線程中調用Control.BeginInvoke

 1         private void btn_Sub_BeginInvoke_Click(object sender, EventArgs e)
 2         {            
 3             //執行順序:
 4             //1、代碼A(主線程執行)
 5             //2、代碼D(主線程執行) 和 代碼B(子線程執行) 並發執行
 6             //3、封裝消息,並在UI線程中注冊消息(子線程執行)
 7             //4、代碼C(子線程執行)
 8             //5、代碼Invoke(主線程執行)
 9 
10             txt_Message.Text = "";
11             txt_Message.Text += "主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始工作\r\n";
12             //代碼A
13             new Thread(() =>
14             {
15                 //代碼B
16                 int temp = 0;
17                 this.txt_Message.BeginInvoke(del);
18                 //代碼C
19                 temp = 1;
20             }).Start();
21             //代碼D
22             txt_Message.Text += "\r\n主線程:" + Thread.CurrentThread.ManagedThreadId + "---開始結束\r\n";
23         }

 

代碼下載


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM