C#Delegate.Invoke、Delegate.BeginInvoke And Control.Invoke、Control.BeginInvoke

本文详细介绍了Delegate与Control的Invoke及BeginInvoke方法的区别与使用场景,通过具体实例演示了不同调用方式下线程的执行流程。

摘自:https://www.cnblogs.com/EasonLeung/p/3683492.html

 

一、Delegate的Invoke、BeginInvoke

1、Delegate.Invoke (委托同步调用)

  a、委托的Invoke方法,在当前线程中执行委托。

  b、委托执行时阻塞当前线程,知道委托执行完毕,当前线程才继续向下执行。

  c、委托的Invoke方法,类似方法的常规调用。

2、Delegate.BeginInvoke (委托异步调用)

  a、委托的BeginInvoke方法,在线程池分配的子线程中执行委托

  b、委托执行时不会阻塞主线程(调用委托的BeginInvoke线程),主线程继续向下执行。

  c、委托执行时会阻塞子线程。

  d、委托结束时,如果有返回值,子线程讲返回值传递给主线程;如果有回调函数,子线程将继续执行回调函数。

3、Demo

  a、Delegate

复制代码

 1         private void btn_General_Click(object sender, EventArgs e)
 2         {
 3             txt_Message.Text = "";
 4             txt_Message.Text += "主线程:"+ Thread.CurrentThread.ManagedThreadId + "---开始工作\r\n";
 5             //委托方法,在调用委托的线程中执行,本例中就是主线程(UI线程)。
 6             //执行一些耗时的操作,就会阻塞主线程(UI线程)
 7             //委托的普通调用就等于方法的直接调用,del();等价于SomeWork();
 8             del();
 9             //SomeWork();
10             txt_Message.Text += "\r\n主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始结束\r\n";
11         }

复制代码

   b、Delegate.Invoke

复制代码

1         private void btn_Main_Invoke_Click(object sender, EventArgs e)
2         {
3             txt_Message.Text = "";
4             txt_Message.Text += "主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始工作\r\n";
5             //委托的同步调用,其实就是等价于委托的普通调用。
6             del.Invoke();
7             txt_Message.Text += "\r\n主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始结束\r\n";
8         }

复制代码

复制代码

 1         private void btn_Sub_Invoke_Click(object sender, EventArgs e)
 2         {
 3             txt_Message.Text = "";
 4             txt_Message.Text += "主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始工作\r\n";
 5 
 6             //开启新的线程执行委托,主线程(UI线程)继续向下执行
 7             new Thread(() => {
 8                 txt_Message.Text += "\r\n----子线程:" + Thread.CurrentThread.ManagedThreadId + "---开始工作\r\n";
 9                 //委托在调用线程中执行,并阻塞调用线程,知道委托方法执行结束。
10                 del.Invoke();
11                 txt_Message.Text += "\r\n----子线程:" + Thread.CurrentThread.ManagedThreadId + "---开始结束\r\n";
12             }).Start();
13 
14             txt_Message.Text += "\r\n主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始结束\r\n";
15         }

复制代码

  c、Delegate.BeginInvoke

复制代码

 1         private void btn_Main_BeginInvoke_Click(object sender, EventArgs e)
 2         {
 3             txt_Message.Text = "";
 4             txt_Message.Text += "主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始工作\r\n";
 5             //委托异步调用
 6             //1、委托方法,在线程池中分配的子线程中执行。
 7             //2、主线程和子线程同时执行。
 8             //3、子线程结束之后,如果有返回值得话,将返回值传递给主线程。如果有回调函数的话,继续在子线程中执行回调函数。
 9 
10             //有异常,控件不能在子线程中访问修改。
11             //避免这类异常有两种方法   
12             //1、手动关闭控件的跨线程安全检查Control.CheckForIllegalCrossThreadCalls = false;(不建议使用)
13             //2、使用控件的Invoke方法。(推荐使用)
14             del.BeginInvoke(null,null);
15             txt_Message.Text += "\r\n主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始结束\r\n";
16         }

复制代码

复制代码

 1         private void btn_Sub_BeginInvoke_Click(object sender, EventArgs e)
 2         {
 3             txt_Message.Text = "";
 4             txt_Message.Text += "主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始工作\r\n";
 5 
 6             //开启新的线程执行委托,主线程(UI线程)继续向下执行
 7             new Thread(() =>
 8             {
 9                 txt_Message.Text += "\r\n----子线程:" + Thread.CurrentThread.ManagedThreadId + "---开始工作\r\n";
10                 //在线程池中分配的子线程中执行委托方法,调用委托的线程继续向下执行。
11                 del.BeginInvoke(null, null); 
12                 txt_Message.Text += "\r\n----子线程:" + Thread.CurrentThread.ManagedThreadId + "---开始结束\r\n";
13             }).Start();
14 
15             txt_Message.Text += "\r\n主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始结束\r\n";
16         }

复制代码

 




作者:EasonLeung

二、Control的Invoke、BeginInvoke

1、Control.Invoke (同步调用)  

  (1)在主线程(UI线程)中调用Control.Invoke

    a、在主线程(UI线程)中调用Control.Invoke,先执行Invoke的方法,再执行Invoke后面的代码。

  (2)在子线程中调用Control.Invoke

    a、子线程中调用Control.Invoke,子线程将调用的方法封装成消息,调用API的RegisterWindowMessage()向UI窗口发送消息。 主线程继续向下执行,子线程处于阻塞状态。

    b、当该消息被主线程执行完成后,子线程才能继续往下执行。

2、Delegate.BeginInvoke (异步调用)

  (1)在主线程(UI线程)中调用Control.BeginInvoke

    a、在主线程(UI线程)中调用Control.BeginInvoke,将调用的方法封装成消息,调用API的RegisterWindowMessage()向UI窗口发送消息。先执行Invoke后面的代码,再执行Invoke的方法。

  (2)在子线程中调用Control.BeginInvoke

    a、子线程中调用Control.BeginInvoke,子线程将调用的方法封装成消息,调用API的RegisterWindowMessage()向UI窗口发送消息。主线程继续向下执行,子线程也继续向下执行。

    b、最后由主线程执行Invoke的方法。

3、Demo

  a、在主线程(UI线程)中调用Control.Invoke

复制代码

 1         private void btn_Main_Invoke_Click(object sender, EventArgs e)
 2         {
 3             //执行顺序:代码A -> 代码Invoke -> 代码B
 4             //都是在主线程中执行
 5 
 6             txt_Message.Text = "";
 7             txt_Message.Text += "主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始工作\r\n";
 8             //代码A
 9             this.txt_Message.Invoke(del);
10             //代码B
11             txt_Message.Text += "\r\n主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始结束\r\n";
12         }

复制代码

  b、在子线程中调用Control.Invoke

复制代码

 1         private void btn_Sub_Invoke_Click(object sender, EventArgs e)
 2         {
 3             //执行顺序:
 4             //1、代码A(主线程执行)
 5             //2、代码D(主线程执行) 和 代码B(子线程执行) 并发执行
 6             //3、封装消息,并在UI线程中注册消息(子线程执行)
 7             //4、代码Invoke(主线程执行)
 8             //5、代码C(子线程执行)
 9 
10             txt_Message.Text = "";
11             txt_Message.Text += "主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始工作\r\n";
12             //代码A
13             new Thread(() =>
14             {
15                 //代码B
16                 int temp = 0;
17                 this.txt_Message.Invoke(del);
18                 //代码C
19                 temp = 1;
20             }).Start();
21             //代码D
22             txt_Message.Text += "\r\n主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始结束\r\n";
23         }

复制代码

  c、在主线程(UI线程)中调用Control.BeginInvoke

复制代码

 1         private void btn_Main_BeginInvoke_Click(object sender, EventArgs e)
 2         {
 3             //执行顺序:代码A -> 封装消息,并在UI线程中注册消息 -> 代码B -> 代码Invoke
 4             //都是在主线程中执行
 5 
 6             txt_Message.Text = "";
 7             txt_Message.Text += "主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始工作\r\n";
 8             //代码A
 9             this.txt_Message.BeginInvoke(del);
10             //代码B
11             txt_Message.Text += "\r\n主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始结束\r\n";
12         }

复制代码

  c、在子线程中调用Control.BeginInvoke

复制代码

 1         private void btn_Sub_BeginInvoke_Click(object sender, EventArgs e)
 2         {            
 3             //执行顺序:
 4             //1、代码A(主线程执行)
 5             //2、代码D(主线程执行) 和 代码B(子线程执行) 并发执行
 6             //3、封装消息,并在UI线程中注册消息(子线程执行)
 7             //4、代码C(子线程执行)
 8             //5、代码Invoke(主线程执行)
 9 
10             txt_Message.Text = "";
11             txt_Message.Text += "主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始工作\r\n";
12             //代码A
13             new Thread(() =>
14             {
15                 //代码B
16                 int temp = 0;
17                 this.txt_Message.BeginInvoke(del);
18                 //代码C
19                 temp = 1;
20             }).Start();
21             //代码D
22             txt_Message.Text += "\r\n主线程:" + Thread.CurrentThread.ManagedThreadId + "---开始结束\r\n";
23         }

复制代码

 

代码下载

计算机技术与测试测量仪器技术的结合,出现了新的测试仪器--虚拟仪器。基于LabVIEW的数据采集系统是第三代自动测试系统的为发展方向数据采集系统可看作是由数据处理部分和数据采集部分组成。在PC机上运用虚拟仪器能共享硬件和软件资源,快速、方便地组建各种数字信号处理系统,并可以方便地利用计算机的强大功能,进行信号分析、数据处理、存储以及图形化显示等,从而实现数据信号的处理。该系统是在NJational InstrumentsCompany推出的一种基于G语言的虚拟仪器软件开发工具 LabVIEW 环境下开发的,针对课题内容编写了数据采集及存储模块,通过对硬件控制程序的编写实现了对非NI驱动硬件的操作,结合具体使用条件编写数据采样程序。系统提供了丰富的数据分析功能,并对系统数据分析功能进行了详细的说明。介绍了数据储存和回放、数据处理、数据采集模块。 数据采集卡部分使用使用DSP来作采集卡CPU具有指令执行厅速度快、总线带宽高、可以完成数据的高速实时处理等优点。最重要的是DSP对于算法的处理有独到的优势,可以在DSP软件中加入一些典型的算法编程,就能够极大的增强系统的信号处理能力。基于以上原因,本设计以TMS320C5402DSP作为采集卡CPU,实现了数据的高速实时传输与处理。 采集卡由DSP完成数字信号处理,FLASH完成系统上电后的的程序加载,通过可编程逻辑器件CPLD完成对DSP外围设备的逻辑控制,利用DSP特有的HPI口与PC进行数据交换。 本文设计了一套基于DSP的数字信号采集卡和基于LabVIEW的PC数据信号处理系统,通过并口实现两者之间的通信,并详细叙述了系统完整的设计过程,从硬件设计和软件设计两方面加以阐述,重点叙述了数字信号采集卡、LabVIEW数据处理和并口通信的设计。
内容概要:本文系统阐述了集成测试在软件测试生命周期中的核心地位与实践方法,全面介绍了集成测试的定义、目标及其在V模型和DevOps中的定位。文章深入剖析了四种主流集成策略——自顶向下、自底向上、三明治和大爆炸集成的实施步骤、优缺点及适用场景,并结合实际案例说明其应用差异。在测试设计方面,提出了覆盖性、数据多样性、独立性和可追溯性四大原则,重点讲解了接口测试、数据流测试和场景驱动测试的设计方法。技术实践部分涵盖了测试环境管理、契约测试、自动化测试工具选型与CI/CD集成,以及缺陷分类与回归验证机制。最后探讨了集成测试面临的环境复杂性、依赖管理、接口频繁变更等挑战,并展望了AI辅助测试、持续测试、混沌工程和可观测性增强等未来发展趋势。; 适合人群:软件测试工程师、开发工程师、质量保障人员,以及从事DevOps实践的技术管理者,尤其适合具有一定测试经验、希望深入掌握集成测试体系的专业人士。; 使用场景及目标:①指导团队选择合适的集成测试策略以提升测试效率;②设计高质量的集成测试用例,有效发现接口缺陷与数据流问题;③构建自动化集成测试流水线,支持敏捷与持续交付;④应对微服务架构下的复杂依赖与接口治理挑战。; 阅读建议:建议结合实际项目背景分章节精读,重点关注策略选择指南与技术实践部分,尝试将契约测试、容器化环境、自动化集成等方法落地到现有CI/CD流程中,并持续关注AI与可观测性等前沿趋势对测试体系的赋能潜力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值