zoukankan      html  css  js  c++  java
  • 关于控件的Invoke(...)方法和BeginInvoke(...)方法的区别

    这两个方法最主要的区别就是一个是同步,一个是异步,即会阻塞线程,那么阻塞哪个线程呢?我们用代码来分析(工具是VS2010)

     1 using System;
     2 using System.Collections.Generic;
     3 using System.ComponentModel;
     4 using System.Data;
     5 using System.Drawing;
     6 using System.Linq;
     7 using System.Text;
     8 using System.Windows.Forms;
     9 using System.Threading;
    10 
    11 namespace Invoke和BeginInvoke
    12 {
    13     public partial class Form1 : Form
    14     {
    15         public Form1()
    16         {
    17             InitializeComponent();
    18         }
    19 
    20         private void button1_Click(object sender, EventArgs e)
    21         {
    22             // HH 是24小时制,hh是12小时制
    23             MessageBox.Show(Thread.CurrentThread.GetHashCode()+" AAA "+DateTime.Now.ToString(" HH.mm.ss.fffff"));
    24             Thread thd = new Thread(ThreadMethod);
    25             thd.IsBackground = true;  // 设置为后台线程,该线程即使没有执行完也会随着主线程退出而退出。
    26             thd.Start();
    27             Thread.Sleep(3000);
    28             MessageBox.Show(Thread.CurrentThread.GetHashCode() + " EEE " + DateTime.Now.ToString(" HH.mm.ss.fffff "));
    29         }
    30 
    31         private void ThreadMethod()
    32         {
    33             MessageBox.Show(Thread.CurrentThread.GetHashCode() + " BBB " + DateTime.Now.ToString("HH.mm.ss.fffff"));
    34             // Invoke会阻塞 ThreadMethod() 所在的线程(子线程)
    35             label1.Invoke(new Action(InvokeMethod));  // Flag
    36             MessageBox.Show(Thread.CurrentThread.GetHashCode() + " DDD " + DateTime.Now.ToString("HH.mm.ss.fffff"));
    37         }
    38 
    39         private void InvokeMethod()
    40         {
    41             MessageBox.Show(Thread.CurrentThread.GetHashCode() + " CCC " + DateTime.Now.ToString("HH.mm.ss.fffff"));
    42         }
    43     }
    44 }

    将上面代码运行后(我这个是个窗体,有个label1和button1,且button1有Click事件),首先是MessageBox.Show(...)会阻塞主线程,如果不按掉AAA的那个显示框不会继续执行代码。

    按掉AAA后立刻出现BBB,然后有两种情况,很重要:

    ①等待3000毫秒的样子出现EEE框,这时候再按掉BBB,这时候会执行InvokeMethod(),该函数是由创建label1的线程来执行。这时候弹出CCC,因为Invoke(...)本身会阻塞子线程ThreadMethod,故没有点掉CCC是不会出现DDD的

    ②点掉AAA后立刻点掉BBB,此时执行ThreadMethod中的label1.Invoke(...),这句代码拥有“两种阻塞”,第一种Invoke本身就是同步函数,故它会阻塞线程ThreadMethod,使得label1.Invoke(...)执行完之前(而它是否执行完又取决于线程InvokeMethod)不会弹出DDD来(即没有按掉CCC前不会弹出DDD)。第二种阻塞就是label1.Invoke是一个很特别的函数,他会使得系统让主线程(因为是主线程创建的label1)来执行label1.Invoke(...)中的方法,即InvokeMethod,而此时主线程正在Sleep(3000),故这段时间内将不会弹出CCC的提示框,等主线程Sleep(3000)完毕后首先弹出的是CCC而不是EEE(即label1.Invoke(...)会将InvokeMethod()放在其所在线程优先执行),

    且情况②如果不点掉CCC不会出现DDD和EEE(这里要注意,尽管不点掉CCC会同时阻塞主线程和子线程,但是阻塞子线程是因为label1.Invoke(...)是同步的,没有执行玩InvokeMethod() Invoke()也不会结束;而阻塞主线程的不是

    Invoke(),而是因为InvokeMethod()是在主线程中执行的,MessageBox.Show(...."CCC"...)阻塞了主线程,与label1.Invoke(...)无关),点掉CCC后,立刻“同时”执行DDD和EEE。

    将Invoke换成BeginInvoke(...)后,同样②情况,上面的阻塞情况不会发生,即 即使CCC没有点掉也会接着执行DDD(因为label1.BeginInvoke(...)不会阻塞ThreadMethod(),但是注意!!!EEE在CCC没有点掉之前是不会执行的(且仍要等主线程Sleep(3000)后才会弹出CCC提示框),因为阻塞EEE的是InvokeMethod()中的MessageBox.Show(.CCC..)。

  • 相关阅读:
    pylab
    通过在 Page 指令或 配置节中设置 validateRequest=false 可以禁用请求验证
    PRIMUS
    Ubuntu 下安装AMBER10/AmberTools 1.2
    SUPCOMB
    biopython
    python IDE
    SASREF
    PEAK
    ANDROID移植: WIFI设计原理(源码分析
  • 原文地址:https://www.cnblogs.com/silentdoer/p/4997700.html
Copyright © 2011-2022 走看看