.c# Invoke和BeginInvoke 区别

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

Control.BeginInvoke 方法 (Delegate) :在创建控件的基础句柄所在线程上异步执行指定委托。

以下为实际应用中碰到的问题,在主线程中启动一个线程,然后在这个线程中启动serviceForm,然而在线程启动后,往serviceForm发送指令,serviceForm.IsHandleCreated老是报serviceForm = null,无法执行指令,采用延时的办法可以解决此问题,但不是高效的办法,后来在serviceForm.Load += new EventHandler(serviceForm_Load);serviceForm_Load事件中添加指令,发送成功。主要原因还是多线程所致。

SatirServiceForm serviceForm;
        Thread serviceFormThread;

protected void Init()
        {
            serviceFormThread = new Thread(MainFormMessageThread);
            serviceFormThread.Name = "ServiceThread";
            serviceFormThread.Start();
        }

protected void MainFormMessageThread()
        {
            if (serviceForm == null)
            {
                serviceForm = new SatirServiceForm();
                serviceForm.Load += new EventHandler(serviceForm_Load);
                //serviceForm.RecvedCmd += new EventHandler(OnServiceRecvedCmd);

}
            Application.Run(serviceForm);
        }

void serviceForm_Load(object sender, EventArgs e)
        {
            SendCommand(InfraOnlineCmd.Start, 0);
            SendCommand(InfraOnlineCmd.AutoAjust, 0);
        }

protected override void SendCommand(InfraOnlineCmd cmd, object param)
        {
            if (param != null && param is int)
                this.param = (int)param;

if (serviceForm.IsHandleCreated)
            {
                serviceForm.BeginInvoke(new DCmdHandler(ExecuteCmd), cmd);
            }
        }

以下ZT From:http://blog.163.com/kjpt126@126/blog/static/48940426200824103658846/

Control的Invoke和BeginInvoke

近日,被Control的Invoke和BeginInvoke搞的头大,就查了些相关的资料,整理如下。感谢这篇文章对我的理解Invoke和BeginInvoke的真正含义 。

(一)Control的Invoke和BeginInvoke

我们要基于以下认识:

(1)Control的Invoke和BeginInvoke与Delegate的Invoke和BeginInvoke是不同的。

(2)Control的Invoke和BeginInvoke的参数为delegate,委托的方法是在Control的线程上执行的,也就是我们平时所说的UI线程。

我们以代码(一)来看(Control的Invoke)

private delegate void InvokeDelegate();

private void InvokeMethod(){

//C代码段

}

private void butInvoke_Click(object sender, EventArgs e) {

//A代码段.......

this.Invoke(new InvokeDelegate(InvokeMethod));

//B代码段......

}

你觉得代码的执行顺序是什么呢?记好Control的Invoke和BeginInvoke都执行在主线程即UI线程上

A------>C---------------->B

解释:(1)A在UI线程上执行完后,开始Invoke,Invoke是同步

(2)代码段B并不执行,而是立即在UI线程上执行InvokeMethod方法,即代码段C。

(3)InvokeMethod方法执行完后,代码段C才在UI线程上继续执行。

看看代码(二),Control的BeginInvoke

private delegate void BeginInvokeDelegate();

private void BeginInvokeMethod(){

//C代码段

}

private void butBeginInvoke_Click(object sender, EventArgs e) {

//A代码段.......

this.BeginInvoke(new BeginInvokeDelegate(BeginInvokeMethod));

//B代码段......

}

你觉得代码的执行顺序是什么呢?记好Control的Invoke和BeginInvoke都执行在主线程即UI线程上

A----------->B--------------->C慎重,这个只做参考。。。。。,我也不肯定执行顺序,如果有哪位达人知道的话请告知。

解释::(1)A在UI线程上执行完后,开始BeginInvoke,BeginInvoke是异步

(2)InvokeMethod方法,即代码段C不会执行,而是立即在UI线程上执行代码段B。

(3)代码段B执行完后(就是说butBeginInvoke_Click方法执行完后),InvokeMethod方法,即代码段C才在UI线程上继续执行。

由此,我们知道:

Control的Invoke和BeginInvoke的委托方法是在主线程,即UI线程上执行的。也就是说如果你的委托方法用来取花费时间长的数据,然后更新界面什么的,千万别在UI线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死。

那么,这个异步到底是什么意思呢?

异步是指相对于调用BeginInvoke的线程异步,而不是相对于UI线程异步,你在UI线程上调用BeginInvoke ,当然不行了。----摘自"Invoke和BeginInvoke的真正涵义"一文中的评论。

BeginInvoke的原理是将调用的方法Marshal成消息,然后调用Win32 API中的RegisterWindowMessage()向UI窗口发送消息。----摘自"Invoke和BeginInvoke的真正涵义"一文中的评论。

(二)我们用Thread来调用BeginInvoke和Invoke

我们开一个线程,让线程执行一些耗费时间的操作,然后再用Control.Invoke和Control.BeginInvoke回到用户UI线程,执行界面更新。

代码(三) Thread调用Control的Invoke

private Thread invokeThread;

private delegate void invokeDelegate();

private void StartMethod(){

//C代码段......

Control.Invoke(new invokeDelegate(invokeMethod));

//D代码段......

}

private void invokeMethod(){

//E代码段

}

private void butInvoke_Click(object sender, EventArgs e) {

//A代码段.......

invokeThread = new Thread(new ThreadStart(StartMethod));

invokeThread.Start();

//B代码段......

}

你觉得代码的执行顺序是什么呢?记好Control的Invoke和BeginInvoke都执行在主线程即UI线程上

A------>(Start一开始B和StartMethod的C就同时执行)---->(C执行完了,不管B有没有执行完,invokeThread把消息封送(invoke)给UI线程,然后自己等待)---->UI线程处理完butInvoke_Click消息后,处理invokeThread封送过来的消息,执行invokeMethod方法,即代码段E,处理往后UI线程切换到invokeThread线程。

这个Control.Invoke是相对于invokeThread线程同步的,阻止了其运行。

解释:

1。UI执行A

2。UI开线程InvokeThread,B和C同时执行,B执行在线程UI上,C执行在线程invokeThread上。

3。invokeThread封送消息给UI,然后自己等待,UI处理完消息后,处理invokeThread封送的消息,即代码段E

4。UI执行完E后,转到线程invokeThread上,invokeThread线程执行代码段D

代码(四) Thread调用Control的BeginInvoke

private Thread beginInvokeThread;

private delegate void beginInvokeDelegate();

private void StartMethod(){

//C代码段......

Control.BeginInvoke(new beginInvokeDelegate(beginInvokeMethod));

//D代码段......

}

private void beginInvokeMethod(){

//E代码段

}

private void butBeginInvoke_Click(object sender, EventArgs e) {

//A代码段.......

beginInvokeThread = new Thread(new ThreadStart(StartMethod));

beginInvokeThread .Start();

//B代码段......

}

你觉得代码的执行顺序是什么呢?记好Control的Invoke和BeginInvoke都执行在主线程即UI线程上

A在UI线程上执行----->beginInvokeThread线程开始执行,UI继续执行代码段B,并发地invokeThread执行代码段C-------------->不管UI有没有执行完代码段B,这时beginInvokeThread线程把消息封送给UI,单自己并不等待,继续向下执行-------->UI处理完butBeginInvoke_Click消息后,处理beginInvokeThread线程封送过来的消息。

解释:

1。UI执行A

2。UI开线程beginInvokeThread,B和C同时执行,B执行在线程UI上,C执行在线程beginInvokeThread上。

3。beginInvokeThread封送消息给UI,然后自己继续执行代码D,UI处理完消息后,处理invokeThread封送的消息,即代码段E

有点疑问:如果UI先执行完毕,是不是有可能过了段时间beginInvokeThread才把消息封送给UI,然后UI才继续执行封送的消息E。如图浅绿的部分。

Control的BeginInvoke是相对于调用它的线程,即beginInvokeThread相对是异步的。

因此,我们可以想到。如果要异步取耗费长时间的数据,比如从数据库中读大量数据,我们应该这么做。

(1)如果你想阻止调用线程,那么调用代码(三),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。

(2)如果你不想阻止调用线程,那么调用代码(四),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。

千万别在UI线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死...相关推荐

  1. 线程实用解析--------(六)Control.Invoke()和Control.BeginInvoke()

    在以前的章节中,我们不只一次的提到过,不能在非创建UI控件的线程中操作UI元素,否则会和UI控件创建线程(一般是主线程)产生冲突,造成不可预料的后果. 该如何解决这个问题呢?除了上一节所讲的Backg ...

  2. WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用 Control 不能在创建它的 Thread 之外被调用。但可以通过 invoke 来保证 C

    WinForm 之Control.Invoke 和Control.BeginInvoke 方法的使用 Control 不能在创建它的 Thread 之外被调用.但可以通过 invoke 来保证 Con ...

  3. Control.Invoke和Control.BeginInvoke

    问题的引入 下面有个简单的demo,大家一看代码就知道效果如何示例.我新建一个winform的程序,然后写入了如下代码: using System; using System.Windows.Form ...

  4. Control.Invoke()和Control.BeginInvoke()

    不能在非创建UI控件的线程中操作UI元素,否则会和UI控件创建线程(一般是主线程)产生冲突,造成不可预料的后果. 该如何解决这个问题呢?除了上一节所讲的BackgroundWorker和Timer以外 ...

  5. android捕获线程异常,android - 终结器引发的未捕获的异常:所有WebView方法必须在同一线程上调用。 (预期的Looper) - 堆栈内存溢出...

    我正在使用Admob SDK 18.1.1 并获得错误终结器抛出未捕获的异常 java.lang.RuntimeException: java.lang.Throwable: A WebView me ...

  6. element ui 图片上传_游民晚播报:PS5手柄续航情况测试 UI界面概览放出

    各位朋友晚上好,现在为您带来今天的晚间播报.一起来回顾一下今天白天游戏圈内外都有哪些要闻.趣闻. 要闻回顾: 1.PS5 DualSense手柄续航情况 触觉反馈密集游戏更耗电 新闻原文:点击查看 P ...

  7. 在.Net中进行跨线程的控件操作(上篇:Control.Invoke)

    本文的重点在于介绍如何在多线程编程中,从非UI线程上访问界面中的控件.有过多线程编程经验的人都知道,当我们在非UI线程上试图给一个界面中的控件赋值的时候,比如说label的Text属性,系统会抛出一个 ...

  8. quot;在创建窗口句柄之前,不能在控件上调用 Invoke 或 BeginInvokequot;

    哎,有接近半年的时候没有真正的写c#程序了,这段时间都写C程序了,看了看UCOS II,有好多不懂的地方,还得挤出时间多看看,看多了不懂的地方就少了.废话好想说多了(老了吧). 今天下午就遇到了这么个 ...

  9. C# this.Invoke()的作用与用法、不阻塞UI界面线程的延时函数

    一.this.Invoke()的作用与用法.不阻塞UI界面线程的延时函数 Invoke()的作用是:在应用程序的主线程上执行指定的委托.一般应用:在辅助线程中修改UI线程( 主线程 )中对象的属性时, ...

最新文章

  1. 十个 Linux 新手管理员易犯错误
  2. Servlet和JSP规范及版本对应关系
  3. 基于IP访问控制的局限性
  4. 获取浏览器书签、浏览器文件夹数据
  5. 超融合将成为数据中心技术应用主流
  6. 从400+节点ElasticSearch集群的运维中,我们总结了这些经验
  7. vue项目打包部署linux_Vue项目打包部署到Nginx服务器
  8. Linux系统时间和java的时间不一致
  9. portlet示例_Java Portlet示例教程
  10. 在ashx文件中使用Session
  11. Win软件 - Listary
  12. 企业如何推动组织变革?
  13. 洛谷P4147 玉蟾宫(单调栈解决)
  14. 基于物理信息深度学习的交通状态估计:以LWR和CTM模型为例
  15. 【MOOC】华中科技大学操作系统慕课答案-单元作业+第1~2章开放性思考题
  16. Nutz cnd.wrap传参
  17. 15位和18位身份证提取出生日期,性别和城市代码
  18. CAPL读取CSV文件,像python一样简单方便
  19. NR DCI Format介绍
  20. c语言去除字符串的空格,C语言实现去除字符串中空格

热门文章

  1. 无所不在的物联网设备 你我都需要正视所带来的安全问题
  2. 全球IT支出保持稳定增长 中国IT支出将超2.3万亿元
  3. 翻转单词顺序与左旋转字符串
  4. WPF学习总结1:INotifyPropertyChanged接口的作用
  5. mongodb常用管理命令
  6. delphi xe2学习笔记(1)
  7. DAS、NAS、SAN、iSCSI 存储方案概述
  8. 百度编辑器(ueditor)上传图片
  9. 浅议 JavaScript 的 Promises/Futures 模式
  10. chrome inspect 离线调试-工具包 怎么使用