C的Invoke与BeginInvoke区别

C的Invoke与BeginInvoke区别分析 浅谈 C 中 Control 的 Invoke 与 BeginInvoke 在主副线程中的执行顺序和区别 SamWang 今天无意中看到有关 Invoke 和 BeginInvoke 的一些资料 不太清楚它们之间的区别 所以花了点时间研究了下 据 msdn 中介绍 它们最大的区别就是 BeginInvoke 属于异步执行的 Control Invoke 方法 Delegate 在拥有此控件的基

【分析】浅谈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 ///  2 /// 直接调用Invoke 3 ///  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 }

复制代码

输出:    

  C的Invoke与BeginInvoke区别

  从输出结果上可以看出,Invoke被调用后,是马上执行的。这点很好理解。

 

  2.主线程调用BeginInvoke

 1 ///  2 /// 直接调用BeginInvoke 3 ///  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 }
  

复制代码

输出:  

  C的Invoke与BeginInvoke区别

  从输出能看出,只有当调用BeginInvoke的线程结束后,才执行它的内容。

 

  不过有两种情况下,它会马上执行:

  使用EndInvoke,检索由传递的 IAsyncResult 表示的异步操作的返回值。

复制代码

 ///  /// 调用BeginInvoke、EndInvoke ///  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--"); }

复制代码

输出:  

  C的Invoke与BeginInvoke区别

   

  同一个控件调用Invoke时,会马上执行先前的BeginInvoke

复制代码

 ///  /// 调用BeginInvoke、Invoke ///  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--"); }

复制代码

输出:

  C的Invoke与BeginInvoke区别

 

  注:在主线程中直接调用Invoke、BeginInvoke、EndInvoke都会造成阻塞。所以应该利用副线程(支线线程)调用。

 

  3.支线线程调用Invoke

  创建一个线程,并在线程中调用Invoke,同时测试程序是在哪个线程中调用Invoke。 

复制代码

 1 ///  2 /// 线程调用Invoke 3 ///  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 }

复制代码

 

输出:  

  C的Invoke与BeginInvoke区别

  • Invoke的委托在主线程中执行
  • Invoke在支线程中调用也会阻塞主线程。(当点击button1后,我试图去点击button2,却发现程序被阻塞了)
  • Invoke还会阻塞支线程。(因为输出结果中没有出现After)  

  接着来测试下在支线程中调用BeginInvoke. 

  4.支线线程调用BeginInvoke 

复制代码

 1 ///  2 /// 线程调用BeginInvoke 3 ///  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 }

复制代码

 

 

输出:    

  C的Invoke与BeginInvoke区别

  • BeginInvoke在主线程中执行。
  • BeginInvoke在支线程中调用也会阻塞主线程。
  • BeginInvoke相对于支线程是异步的。 

 

总结:  

  以下为了方便理解,假设如下:

    主线程表示Control.Invoke或Control.BeginInvoke中Control所在的线程,即创建该创建的线程。(一般为UI线程)

    支线程表示不同于主线程的调用Invoke或BeginInvoke的线程。

  • Control的Invoke和BeginInvoke的委托方法是在主线程,即UI线程上执行。(也就是说如果你的委托方法用来取花费时间长的数据,然后更新界面什么的,千万别在主线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死)
  • Invoke会阻塞主支线程,BeginInvoke只会阻塞主线程,不会阻塞支线程!因此BeginInvoke的异步执行是指相对于支线程异步,而不是相对于主线程异步。(从最后一个例子就能看出,程序运行点击button1)
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/209572.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 上午8:56
下一篇 2026年3月19日 上午8:56


相关推荐

  • ubuntu搭建samba服务器_搭建webdav

    ubuntu搭建samba服务器_搭建webdav1、下载安装samba服务sudoapt-getinstallsamba2、修改smb配置文件,设置共享目录a)配置文件:/etc/samba/smb.confb)进到该目录:cd/etc/sambac)修改前备份:sudocpsmb.confsmb.conf_bakd)修改配置文件,设置共享目录:sudovismb.conf参考修改内容(例:共享目录/home/samba_share)[samba_share]comment=…

    2026年3月8日
    3
  • Qt 之图形(QPainter 的基本绘图)「建议收藏」

    Qt 之图形(QPainter 的基本绘图)「建议收藏」Qt中提供了强大的2D绘图系统,可以使用相同的API在屏幕和绘图设备上进行绘制,它主要基于QPainter、QPaintDevice和QPaintEngine这三个类。-QPainter用于执行绘图操作,其提供的API在GUI或QImage、QOpenGLPaintDevice、QWidget和QPaintDevice显示图形(线、形状、渐变等)、文本和图像。

    2025年8月2日
    6
  • 用HTML5做的导航条(步骤非常详细)

    用HTML5做的导航条(步骤非常详细)转载请注明出处:这里写链接内容首先准备网页背景图片和导航背景图片,放在同一目录下的images文件夹中编写html文件

    2022年5月8日
    48
  • Github复现之TransUnet更新[通俗易懂]

    Github复现之TransUnet更新[通俗易懂]上一篇关于TransUnet的GitHub复现,大家反映效果不好,调参也不好调,我把模型单独拿出来,放到另外一个框架,供大家参考学习(上一篇链接:https://blog.csdn.net/qq_20373723/article/details/115548900)我这里训练了20个epoch,下面先给出效果正常的情况:原图预测结果整体代码结构:1.数据准备,文件名字请务必保持一致,不过你也可以去代码里改一级目录,红线的三个,其它不用管二级目录三级目录就是图像和标签,二者名字保持一

    2025年9月19日
    5
  • vite详解

    vite详解一 认识 vitewebpack 是目前整个前端使用最多的构建工具 但是除了 webpack 之后也存在其他一些构建工具 比如说 rollup parcel gulp vite 等等 vite 的官方定位是下一代前端开发和构建工具 如何定义下一代开发和构建工具呢 我们知道在实际开发中 我们在编写的代码往往是不能被浏览器直接识别的 比如 ES6 TypeScript Vue 文件等 所以此时我们必须通过构建工具来对代码进行转换 编译 类似的工具有 webpack rollup parcel 但是随着项目越来越大 需要处理的

    2026年3月20日
    3
  • 计算机上的32位是什么意思啊,解答32位是什么意思

    计算机上的32位是什么意思啊,解答32位是什么意思近来有不少网友询问电脑中的 32 位是什么意思 我们在安装操作系统的时候 经常会被问到电脑是 32 位还是 64 位这个问题 可是我们连 32 位的意思都不懂 怎么能选择一个合适的操作系统呢 对此 我给大家整理了 32 位的相关介绍 赶紧来瞧瞧吧现在家家户户都配置了电脑 但是很多朋友对于电脑方面的知识却不怎么了解 比如现在的电脑分为 32 位和 64 位 有些小伙伴不知这是什么意思 接下来 我就给大家介绍一下 32 位到底是什么

    2026年3月19日
    1

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号