日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > C# >内容正文

C#

【分析】浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang)

發布時間:2023/12/18 C# 22 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【分析】浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

  今天無意中看到有關Invoke和BeginInvoke的一些資料,不太清楚它們之間的區別。所以花了點時間研究了下。

  據msdn中介紹,它們最大的區別就是BeginInvoke屬于異步執行的。

  • Control.Invoke 方法 (Delegate) :在擁有此控件的基礎窗口句柄的線程上執行指定的委托。
  • Control.BeginInvoke 方法 (Delegate) :在創建控件的基礎句柄所在線程上異步執行指定委托。
msdn說明:

控件上的大多數方法只能從創建控件的線程調用。?如果已經創建控件的句柄,則除了?InvokeRequired?屬性以外,控件上還有四個可以從任何線程上安全調用的方法,它們是:Invoke、BeginInvoke、EndInvoke?和?CreateGraphics。?在后臺線程上創建控件的句柄之前調用?CreateGraphics?可能會導致非法的跨線程調用。?對于所有其他方法調用,則應使用調用 (invoke) 方法之一封送對控件的線程的調用。?調用方法始終在控件的線程上調用自己的回調。

  

  于是用下面的代碼進行初步的測試:  

  1.主線程調用Invoke   

1 /// <summary> 2 /// 直接調用Invoke 3 /// </summary> 4 private void TestInvoke() 5 { 6 listBox1.Items.Add("--begin--"); 7 listBox1.Invoke(new Action(() => 8 { 9 listBox1.Items.Add("Invoke"); 10 })); 11 12 Thread.Sleep(1000); 13 listBox1.Items.Add("--end--"); 14 }

輸出:    

  

  從輸出結果上可以看出,Invoke被調用后,是馬上執行的。這點很好理解。

?

  2.主線程調用BeginInvoke

1 /// <summary> 2 /// 直接調用BeginInvoke 3 /// </summary> 4 private void TestBeginInvoke() 5 { 6 listBox1.Items.Add("--begin--"); 7 var bi = listBox1.BeginInvoke(new Action(() => 8 { 9 //Thread.Sleep(10000); 10 listBox1.Items.Add("BeginInvoke"); 11 })); 12 Thread.Sleep(1000); 13 listBox1.Items.Add("--end--"); 14 }

輸出:  

  

  從輸出能看出,只有當調用BeginInvoke的線程結束后,才執行它的內容。

?

  不過有兩種情況下,它會馬上執行:

  使用EndInvoke,檢索由傳遞的?IAsyncResult?表示的異步操作的返回值。

/// <summary>/// 調用BeginInvoke、EndInvoke/// </summary>private void TestBeginInvokeEndInvoke(){listBox1.Items.Add("--begin--");var bi = listBox1.BeginInvoke(new Action(() =>{Thread.Sleep(1000);listBox1.Items.Add("BeginInvokeEndInvoke");}));listBox1.EndInvoke(bi);listBox1.Items.Add("--end--");}

輸出:  

  

?  

  同一個控件調用Invoke時,會馬上執行先前的BeginInvoke

/// <summary>/// 調用BeginInvoke、Invoke/// </summary>private void TestBeginInvokeInvoke(){listBox1.Items.Add("--begin--");listBox1.BeginInvoke(new Action(() =>{Thread.Sleep(1000);listBox1.Items.Add("BeginInvoke");}));listBox1.Invoke(new Action(() =>{listBox1.Items.Add("Invoke");}));listBox1.Items.Add("--end--");}

輸出:

  

?

  注:在主線程中直接調用Invoke、BeginInvoke、EndInvoke都會造成阻塞。所以應該利用副線程(支線線程)調用。

?

  3.支線線程調用Invoke

  創建一個線程,并在線程中調用Invoke,同時測試程序是在哪個線程中調用Invoke。?

1 /// <summary> 2 /// 線程調用Invoke 3 /// </summary> 4 private void ThreadInvoke() 5 { 6 listBox1.Items.Add("--begin--"); 7 new Thread(() => 8 { 9 Thread.CurrentThread.Name = "ThreadInvoke"; 10 string temp = "Before!"; 11 listBox1.Invoke(new Action(() => 12 { 13 Thread.Sleep(10000); 14 this.listBox1.Items.Add(temp +="Invoke!" + Thread.CurrentThread.Name); 15 })); 16 temp += "After!"; 17 }).Start(); 18 listBox1.Items.Add("--end--"); 19 } 20 21 22 private void button1_Click(object sender, EventArgs e) 23 { 24 Thread.CurrentThread.Name = "Main"; 25 ThreadInvoke(); 26 } 27 28 private void button2_Click(object sender, EventArgs e) 29 { 30 listBox1.Items.Add("button2_Click"); 31 }

?

輸出:  

  

  • Invoke的委托在主線程中執行
  • Invoke在支線程中調用也會阻塞主線程。(當點擊button1后,我試圖去點擊button2,卻發現程序被阻塞了)
  • Invoke還會阻塞支線程。(因為輸出結果中沒有出現After)  

  接著來測試下在支線程中調用BeginInvoke.?

  4.支線線程調用BeginInvoke?

1 /// <summary> 2 /// 線程調用BeginInvoke 3 /// </summary> 4 private void ThreadBeginInvoke() 5 { 6 listBox1.Items.Add("--begin--"); 7 new Thread(() => 8 { 9 Thread.CurrentThread.Name = "ThreadBeginInvoke"; 10 string temp = "Before!"; 11 listBox1.BeginInvoke(new Action(() => 12 { 13 Thread.Sleep(10000);
14 this.listBox1.Items.Add(temp += "Invoke!" + Thread.CurrentThread.Name); 15 })); 17 temp += "After!"; 18 }).Start(); 19 listBox1.Items.Add("--end--"); 20 } 21 22 23 private void button1_Click(object sender, EventArgs e) 24 { 25 Thread.CurrentThread.Name = "Main"; 26 ThreadBeginInvoke(); 27 } 28 29 private void button2_Click(object sender, EventArgs e) 30 { 31 listBox1.Items.Add("button2_Click"); 32 }

?

?

輸出:    

  

  • BeginInvoke在主線程中執行。
  • BeginInvoke在支線程中調用也會阻塞主線程。
  • BeginInvoke相對于支線程是異步的。?

?

總結:  

  以下為了方便理解,假設如下:

    主線程表示Control.Invoke或Control.BeginInvoke中Control所在的線程,即創建該創建的線程。(一般為UI線程)

    支線程表示不同于主線程的調用Invoke或BeginInvoke的線程。

  • Control的Invoke和BeginInvoke的委托方法是在主線程,即UI線程上執行。(也就是說如果你的委托方法用來取花費時間長的數據,然后更新界面什么的,千萬別在主線程上調用Control.Invoke和Control.BeginInvoke,因為這些是依然阻塞UI線程的,造成界面的假死)
  • Invoke會阻塞主支線程,BeginInvoke只會阻塞主線程,不會阻塞支線程!因此BeginInvoke的異步執行是指相對于支線程異步,而不是相對于主線程異步。(從最后一個例子就能看出,程序運行點擊button1)

                                       SamWang

?                                      2012-05-25

?

作者:SamWang?
出處:http://wangshenhe.cnblogs.com/?
本文版權歸作者和博客園共有,歡迎圍觀轉載。轉載時請您務必在文章明顯位置給出原文鏈接,謝謝您的合作。

?

  

?

?

  

  

分類:?C#,原創 標簽:?C#,?SamWang,?區別,?Invoke,?BeginInvoke,?執行順序,?異步執行 好文要頂?關注我?收藏該文?? SamWang
關注 - 5
粉絲 - 160 +加關注 13 0 ??上一篇:【筆記】《編寫高質量代碼:改善c#程序的157個建議》-第1章 基本語言要素(SamWang)
??下一篇:[轉]VS隱藏的快捷鍵和小功能
posted on?2012-05-25 09:28?SamWang?閱讀(14262) 評論(11)?編輯?收藏
評論: #1樓?2012-05-25 11:27?|?Tommy_金博?
分析的好~感謝分享 支持(0)反對(0) ?? #2樓?2012-05-25 13:17?|?fupei101011?
引用Invoke被調用時就會直接執行,也就是直接阻塞線程(包括主支線程),直到它結束。而BeginInvoke只有等支線程結束或者調用EndInvoke、Invoke時才會開始執行。
假如這里所謂的“主線程”是指創建控件的線程。所謂“支線程”是指不同于主線程而且是調用begininvoke/invoke的線程。
beginInvoke和invoke所執行的委托是在主線程中執行的。但invoke會阻塞線程,beginInvoke則不會。他們將到windows消息隊列中排隊等待。所以beginInvoke之后,該委托將和支線程之后的代碼并發執行,而不存在你所說的先后問題。該委托在主線程中執行所以也不存在什么阻塞主線程這個說法。
至于在運行結果中出現了 Before!After!Main ,這并能說明BeginInvoke的委托一定是在線程結束以后執行。出現這個結果的主要原因在于 引用Thread.Sleep(1000);這句代碼,讓主線程睡眠了一秒鐘。正如前面所說,委托在主線程windows消息隊列中,主線程睡眠,它當然要等一秒后,直到當前事件button1_Click執行完了,才能可能輪到他。而支線程恰好用著一秒中時間執行完了。所以讓你誤認為是beginInvoke回調的委托肯定是在支線程執行完后才會執行。你可以在 引用temp += "After!";之前加Thread.Sleep(10000);結果很可能就是Before!Main! 支持(0)反對(0) ?? #3樓?2012-05-25 14:06?|?smark?
其實沒有必要這樣測試去判斷,看下代碼就最了解了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 [EditorBrowsable(EditorBrowsableState.Advanced)] public?IAsyncResult BeginInvoke(Delegate method,?params?object[] args) { ????IAsyncResult result; ????using?(new?Control.MultithreadSafeCallScope()) ????{ ????????Control control =?this.FindMarshalingControl(); ????????result = (IAsyncResult)control.MarshaledInvoke(this, method, args,?false); ????} ????return?result; } // System.Windows.Forms.Control public?object?Invoke(Delegate method,?params?object[] args) { ????object?result; ????using?(new?Control.MultithreadSafeCallScope()) ????{ ????????Control control =?this.FindMarshalingControl(); ????????result = control.MarshaledInvoke(this, method, args,?true); ????} ????return?result; }

再細看一下MarshaledInvoke代碼就知道都是做了些什么

總結

以上是生活随笔為你收集整理的【分析】浅谈C#中Control的Invoke与BeginInvoke在主副线程中的执行顺序和区别(SamWang)的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 人妻丝袜一区二区三区 | 色播久久| 欧美一区二区三区粗大 | 娇妻高潮浓精白浆xxⅹ | 992tv在线成人免费观看 | 亚洲你懂的 | 亚洲偷 | 干欧美少妇 | 久久久精品视频网站 | 精品无码在线视频 | 五月激情综合婷婷 | 久久精品1 | 国产一级片毛片 | 涩天堂 | 天天爽夜夜爽夜夜爽 | 日本精品一区在线观看 | 淫语对白 | 国产精品欧美久久久久天天影视 | 欧美视频第一页 | 国产又大又黑又粗 | 五月深爱网 | 国产又粗又猛又黄 | 欧美日韩一区视频 | 日本激情网站 | 乱淫av | 天堂网中文字幕 | 国产精品综合网 | 国产黑丝av| 久久极品视频 | 一道本av在线 | 在线观看av大片 | 国产成人一区二区三区免费看 | 玉女心经是什么意思 | 麻豆免费观看网站 | 免费av网址在线观看 | 亚洲天堂视频在线播放 | 奇米色在线 | 激情图片在线观看 | 秋霞国产午夜精品免费视频 | 国产一区二区三区亚洲 | 精品网站| 亚洲av不卡一区二区 | 色悠悠av | 可以免费观看的毛片 | 麻豆精品一区二区三区 | www.伊人.com| 激情欧美一区二区三区 | 丁香激情小说 | 爱情岛论语亚洲入口 | 中文字幕影院 | 日本男女激情视频 | 欧美91视频 | 可以免费看的黄色网址 | 国产91精品一区 | 欧美性视频一区二区 | 欧美cccc极品丰满hd | xvideos成人免费视频 | 亚洲精品wwww| 中国av免费| 一本大道久久 | 国产精品91一区 | 熟妇女人妻丰满少妇中文字幕 | 韩国日本在线观看 | 男女激情视频网站 | 97桃色| 8ppav | 韩国在线不卡 | 在线免费观看a级片 | www.-级毛片线天内射视视 | 人人模人人爽 | 久久精品国产亚洲AV成人雅虎 | 精品一区二区三区蜜臀 | 免费三片在线视频 | 国产亚洲自拍一区 | 丁香花免费高清完整在线播放 | 欧美性视频在线 | 精品国产影院 | 成人在线高清 | 插插操操| 欧美xxxxhd| 欧美无遮挡高潮床戏 | 欧美色xxxxx 日本精品一区二区三区四区的功能 | 黄色福利视频网站 | 口述3p做爰全过程 | 午夜日韩电影 | 国产精品探花一区二区在线观看 | 欧美女人交配视频 | 午夜影院一区 | 婷婷综合精品 | 中文字幕在线观看视频一区 | 情五月 | 男女ss视频 | 大香焦久久 | 丰满人妻一区二区三区大胸 | 日本大尺度激情做爰hd | 亚洲一区精品在线观看 | 欧美综合图片 | 亚洲综合丁香 | 强行挺进白丝老师翘臀网站 |