【分析】浅谈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         /// 直接调用Invoke3         /// </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         /// 直接调用BeginInvoke3         /// </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         /// 线程调用Invoke3         /// </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         /// 线程调用BeginInvoke3         /// </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)

C#的Invoke与BeginInvoke区别相关推荐

  1. C#——invoke和begininvoke 区别

    invoke和begininvoke 区别 一直对invoke和begininvoke的使用和概念比较混乱,这两天看了些资料,对这两个的用法和原理有了些新的认识和理解. 首先说下,invoke和beg ...

  2. c# Invoke和BeginInvoke 区别

    转自http://www.cnblogs.com/c2303191/articles/826571.html Control.Invoke 方法 (Delegate) :在拥有此控件的基础窗口句柄的线 ...

  3. c# Invoke和BeginInvoke 区别详解

    Control.Invoke 方法 (Delegate):在拥有此控件的基础窗口句柄的线程上执行指定的委托. Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句柄 ...

  4. C#:invoke 与 BeginInvoke使用区别

    invoke和begininvoke 区别 一直对invoke和begininvoke的使用和概念比较混乱,这两天看了些资料,对这两个的用法和原理有了些新的认识和理解. 首先说下,invoke和beg ...

  5. c# Invoke和BeginInvoke

    *************************************************** 更多精彩,欢迎进入:http://shop115376623.taobao.com ****** ...

  6. c# Invoke 与BeginInvoke 的用法

    最近在学习线程时,发现当我创建的线程需要访问UI界面的时,会发生异常,原因是我在跨线程调用主线程的控件,因此windows GUI编程有一个规则,就是只能通过创建控件的线程来操作控件的数据,否则就可能 ...

  7. c# Invoke 与BeginInvoke 的用法(通俗易懂,最全)

    ** c# Invoke 与BeginInvoke 的用法 ** 最近在学习线程时,发现当我创建的线程需要访问UI界面的时,会发生异常,原因是我在跨线程调用主线程的控件,因此windows GUI编程 ...

  8. C# invoke 和 begininvoke 用法

    invoke和begininvoke 区别 一直对invoke和begininvoke的使用和概念比较混乱,这两天看了些资料,对这两个的用法和原理有了些新的认识和理解. 首先说下,invoke和beg ...

  9. C#中Invoke 和 BeginInvoke的涵义和区别

    BeginInvoke 方法真的是新开一个线程进行异步调用吗? 参考以下代码: public delegate void treeinvoke(); private void UpdateTreeVi ...

最新文章

  1. Bzoj2141: 排队
  2. zpl代码可以编译的特殊字符_国际C语言混乱代码大赛(IOCCC)代码解析
  3. 华为手机相册怎么镜像翻转_怎么利用手机相册制作电子视频
  4. Vue学习笔记:使用CLI构建Vue项目
  5. 什么舱位_把“订舱位”说成book warehouse position,外企不会要你
  6. IntelliJ IDEA使用教程 (总目录篇)
  7. 日志易——中国版的splunk
  8. 一篇关于微信防撤回(文本、图片、语音、视频、名片等...)的Python学习教程
  9. 机器学习系列(13)_PCA对图像数据集的降维_02
  10. windows无法开启网络发现问题解决办法(详细)
  11. 柚鸥ASO优化:aso搜索优化怎么做
  12. 64位系统可以装python32位吗_Python - pyinstaller在64位系统下打包32位程序
  13. 英语词根词缀记忆法(全集)_掌握了英语词根词缀,就能迅速记下单词,快速提升词汇量...
  14. 思维题:一个岛上有100个人,95个蓝眼睛,5个红眼睛
  15. 超体分享 | 迭代思维:你感觉原地踏步,只是因为你想一步到位
  16. 等额本金、等额本息工具类(Java版)
  17. OSDev——Bare Bones
  18. BZOJ1202 狡猾的商人 (Floyd)
  19. unable to dequeue a cell with identifier xxx - must register a nib or a class fo
  20. Xcode 使用笔记

热门文章

  1. 指令系统——指令格式
  2. 第十九篇 | Linux命令之ps/kill/top
  3. table表格直接导出Excel文件
  4. java编程10以内随机数字乘除_随机生成10个长度为10以内的字符串并排序(Java入门第三季集合下作...
  5. Pycharm Professional2018.3版安装教程
  6. BCD-七段数码管显示译码器
  7. oops linux 内核,Linux内核的Oops
  8. LeetCode笔记:Biweekly Contest 33 比赛记录
  9. 塑胶模具基本知识以及技术应用
  10. Matlab画图希腊字母显示