转载:https://www.cnblogs.com/c2303191/articles/826571.html

近日,被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改为更新界面的方法。

相关知识:1。Invoke 和 BeginInvoke 的真正涵义

最新文章

  1. uva11292 Dragon of Loowater
  2. WAF绕过小结
  3. 还是畅通工程(MST)
  4. [原创] 分享一些linux教程
  5. 在中国Windows Azure服务中创建应用程序的一些不同之处
  6. lambda -- Filter Java Stream to 1 and only 1 element
  7. 浅谈web前端就业的学习路线
  8. Spring Security(13)——session管理
  9. 大大维的游戏机计划3--2048v1
  10. 把上传Github的代码添加Cocoapods支持
  11. Groovy语言学习--语法基础(3)
  12. 洛谷P3242 接水果 [HNOI2015] 整体二分
  13. [内核驱动] DOS路径转化为NT路径
  14. [转] 常用的CSS命名规则
  15. UVa 10870 Recurrences (矩阵快速幂)
  16. linux通过wget直接下载jdk
  17. PAT 1066. Root of AVL Tree (25)
  18. 半小时分组统计个数sql
  19. 当Appium中遇到alert(python篇)
  20. 30行代码实现js原生三级联动菜单

热门文章

  1. codeforces 576C Points on Plane 相邻两点的欧拉距离
  2. 平衡搜索树-B树。
  3. MySQL用户
  4. mysql:where和having的区别
  5. spring-boot的三种启动方式
  6. android启动模拟器命令
  7. 8.JavaScript
  8. 【CUDA 基础】3.4 避免分支分化
  9. Python excel文件操作,编程练习题实例七十五
  10. mock的那点事