委托线程

本系列教程主要包括如下内容:

1.  BeginInvoke
和EndInvoke方法

2.  Thread类

3. 线程池

4. 线程同步基础

5. 死锁

6. 线程同步的7种方法

7. 如何在线程中访问GUI组件

一、线程概述

在操作系统中一个进程至少要包含一个线程,然后,在某些时候需要在同一个进程中同时执行多项任务,或是为了提供程序的性能,将要执行的任务分解成多个子任务执行。这就需要在同一个进程中开启多个线程。我们使用C#编写一个应用程序(控制台或桌面程序都可以),然后运行这个程序,并打开windows任务管理器,这时我们就会看到这个应用程序中所含有的线程数,如下图所示。



如果任务管理器没有“线程数”列,可以【查看】>【选择列】来显示“线程计数”列。从上图可以看出,几乎所有的进程都拥有两个以上的线程。从而可以看出,线程是提供应用程序性能的重要手段之一,尤其在多核CPU的机器上尤为明显。

二、用委托(Delegate)的BeginInvoke和EndInvoke方法操作线程

 

在C#中使用线程的方法很多,使用委托的BeginInvoke和EndInvoke方法就是其中之一。BeginInvoke方法可以使用线程异步地执行委托所指向的方法。然后通过EndInvoke方法获得方法的返回值(EndInvoke方法的返回值就是被调用方法的返回值),或是确定方法已经被成功调用。我们可以通过四种方法从EndInvoke方法来获得返回值。

三、直接使用EndInvoke方法来获得返回值

    当使用BeginInvoke异步调用方法时,如果方法未执行完,EndInvoke方法就会一直阻塞,直到被调用的方法执行完毕。如下面的代码所示:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace MyThread
{
    
class Program
    {
        
private static int newTask(int ms)
        {
            Console.WriteLine(
"任务开始");
            Thread.Sleep(ms);
            Random random 
= new Random();
            
int n = random.Next(10000);
            Console.WriteLine(
"任务完成");
            
return n;
        }

        
private delegate int NewTaskDelegate(int ms);
             
        
        
static void Main(string[] args)
        {
            NewTaskDelegate task 
= newTask;
            IAsyncResult asyncResult 
= task.BeginInvoke(2000, null, null);

            // EndInvoke方法将被阻塞2秒
            int result = task.EndInvoke(asyncResult);           
            Console.WriteLine(result);
        }
    }
}

    在运行上面的程序后,由于newTask方法通过Sleep延迟了2秒,因此,程序直到2秒后才输出最终结果(一个随机整数)。如果不调用EndInvoke方法,程序会立即退出,这是由于使用BeginInvoke创建的线程都是后台线程,这种线程一但所有的前台线程都退出后(其中主线程就是一个前台线程),不管后台线程是否执行完毕,都会结束线程,并退出程序。关于前台和后台线程的详细内容,将在后面的部分讲解。

    读者可以使用上面的程序做以下实验。首先在Main方法的开始部分加入如下代码:

Thread.Sleep(10000);

    以使Main方法延迟10秒钟再执行下面的代码,然后按Ctrl+F5运行程序,并打开企业管理器,观察当前程序的线程数,假设线程数是4,在10秒后,线程数会增至5,这是因为调用BeginInvoke方法时会建立一个线程来异步执行newTask方法,因此,线程会增加一个。

四、使用IAsyncResult asyncResult属性来判断异步调用是否完成

    
虽然上面的方法可以很好地实现异步调用,但是当调用EndInvoke方法获得调用结果时,整个程序就象死了一样,这样做用户的感觉并不会太好,因此,我们可以使用asyncResult来判断异步调用是否完成,并显示一些提示信息。这样做可以增加用户体验。代码如下:

static void Main(string[] args)
{
    NewTaskDelegate task 
= newTask;
    IAsyncResult asyncResult 
= task.BeginInvoke(2000, null, null);
 
    
while (!asyncResult.IsCompleted)
    {
        Console.Write(
"*");
        Thread.Sleep(
100);
    }
    
// 由于异步调用已经完成,因此, EndInvoke会立刻返回结果
    int result = task.EndInvoke(asyncResult);           
    Console.WriteLine(result);
}


    上面代码的执行结果如下图所示。



    由于是异步,所以“*”可能会在“任务开始”前输出,如上图所示。


五、使用WaitOne方法等待异步方法执行完成

    
使用WaitOne方法是另外一种判断异步调用是否完成的方法。代码如下:

static void Main(string[] args)
{
    NewTaskDelegate task 
= newTask;
    IAsyncResult asyncResult 
= task.BeginInvoke(2000, null, null);

    
while (!asyncResult.AsyncWaitHandle.WaitOne(100, false))
    {
         Console.Write(
"*");              
    }

    
int result = task.EndInvoke(asyncResult);
    Console.WriteLine(result);
}

    WaitOne的第一个参数表示要等待的毫秒数,在指定时间之内,WaitOne方法将一直等待,直到异步调用完成,并发出通知,WaitOne方法才返回true。当等待指定时间之后,异步调用仍未完成,WaitOne方法返回false,如果指定时间为0,表示不等待,如果为-1,表示永远等待,直到异步调用完成。

六、使用回调方式返回结果

    上面介绍的几种方法实际上只相当于一种方法。这些方法虽然可以成功返回结果,也可以给用户一些提示,但在这个过程中,整个程序就象死了一样(如果读者在GUI程序中使用这些方法就会非常明显),要想在调用的过程中,程序仍然可以正常做其它的工作,就必须使用异步调用的方式。下面我们使用GUI程序来编写一个例子,代码如下:

private delegate int MyMethod();
private int method()
{
    Thread.Sleep(
10000);
    
return 100;
}
private void MethodCompleted(IAsyncResult asyncResult)
{
    
if (asyncResult == null) return;
    textBox1.Text 
= (asyncResult.AsyncState as 
    MyMethod).EndInvoke(asyncResult).ToString();
}

private void button1_Click(object sender, EventArgs e)
{

    MyMethod my 
= method;
    IAsyncResult asyncResult 
= my.BeginInvoke(MethodCompleted, my);
}

    要注意的是,这里使用了BeginInvoke方法的最后两个参数(如果被调用的方法含有参数的话,这些参数将作为BeginInvoke的前面一部分参数,如果没有参数,BeginInvoke就只有两个参数了)。第一个参数是回调方法委托类型,这个委托只有一个参数,就是IAsyncResult,如MethodCompleted方法所示。当method方法执行完后,系统会自动调用MethodCompleted方法。BeginInvoke的第二个参数需要向MethodCompleted方法中传递一些值,一般可以传递被调用方法的委托,如上面代码中的my。这个值可以使用IAsyncResult.AsyncState属性获得。

    由于上面的代码通过异步的方式访问的form上的一个textbox,因此,需要按ctrl+f5运行程序(不能直接按F5运行程序,否则无法在其他线程中访问这个textbox,关于如果在其他线程中访问GUI组件,并在后面的部分详细介绍)。并在form上放一些其他的可视控件,然在点击button1后,其它的控件仍然可以使用,就象什么事都没有发生过一样,在10秒后,在textbox1中将输出100。

七、其他组件的BeginXXX和EndXXX方法

    在其他的.net组件中也有类似BeginInvoke和EndInvoke的方法,如System.Net.HttpWebRequest类的BeginGetResponse和EndGetResponse方法,下面是使用这两个方法的一个例子:

private void requestCompleted(IAsyncResult asyncResult)
{
    
if (asyncResult == null) return;
    System.Net.HttpWebRequest hwr 
= asyncResult.AsyncState as System.Net.HttpWebRequest;
    System.Net.HttpWebResponse response 
= 
(System.Net.HttpWebResponse)hwr.EndGetResponse(asyncResult);
    System.IO.StreamReader sr 
= new 
System.IO.StreamReader(response.GetResponseStream());
    textBox1.Text 
= sr.ReadToEnd();
}
private delegate System.Net.HttpWebResponse RequestDelegate(System.Net.HttpWebRequest request);

private void button1_Click(object sender, EventArgs e)
{
    System.Net.HttpWebRequest request 
= 
    (System.Net.HttpWebRequest)System.Net.WebRequest.Create(
"http://www.cnblogs.com");
    IAsyncResult asyncResult 
=request.BeginGetResponse(requestCompleted, request);     
}
c# Invoke 与BeginInvoke 的用法(通俗易懂,最全) *c# Invoke 与BeginInvoke 的用法大全 阅读详情

相关推荐

C#中委托回调,事件方法

定义委托 delegate 返回值 方法签名 delegate void Handler();   创建实例 Handler handler = new Handler(Fun); 调用委托 handler(); 委托实现方法的异步调用 同步调用方法:排队调用,前一个方法执行时,后一个方法等待它的结束后才能启动 异步调用方法:不排队调用,前一个方法如果异步调用,后一个方法不必等...

liudavi的博客 1353

[C#基础]c#中的BeginInvoke和EndEndInvoke

摘要 异步这东西,真正用起来的时候,发现事情还是挺多的,最近在项目中用到了异步的知识,发现对它还是不了解,处理起来,走了不少弯路。觉得还是补一补还是很有必要的。 MSDN原文地址:https://msdn.microsoft.com/en-us/library/2e08f6yc(v=vs.110).aspx 正文 .Net framework可以让你异步调用任何方法。为达这样的目的,你可以...

weixin_34014555的博客 1585

C#中实现多线程委托的具体指南

本文还有配套的精品资源,点击获取 简介:在C#编程中,多线程和委托是提高应用程序性能和响应性的关键概念。本文将介绍如何在Windows Forms应用中利用这些概念,以按钮点击事件为例,通过主线程和新建线程分别向listview控件添加数据。内容涵盖线程创建与管理、委托的使用、事件和异步操作,以及如何安全地从多线程中更新UI控件。 1. 多线程概念与C#实现 ...

weixin_42513870的博客 927

c#学习系列相关之多线程(三)----invoke和begininvoke

本文具体介绍了begininvoke异步的过程,同时和invoke 的对比

qiaodahua的博客 6223

C#线程 BeginInvoke和EndInvoke使用方法

本文开始C#线程系列讲座之一,即BeginInvoke和EndInvoke的使用方法,需要的朋友可以参考下

AD620单电源应变片测量电路分析

笔者最近在用AD620做应变片的压力检测电路,正好AD620的datasheet中有对于应变片压力测量的应用电路,参考该电路进行设计及实验后发现该电路存在些许问题,并对其进行了优化改进。本文纯属个人理解,供大家参考,欢迎批评指正。 AD620应用电路分析及优化 应用电路分析 AD620手册中原电路如下(加了部分标注以便分析): 该电路中,前半部分比较明显,为经典的AD620放大电路结构:四个应变...

拙诚电子工作室 1万+

VB.Net的多线程及委托

VB.Net的多线程及委托   一、多线程:在一个程序中,这些独立运行的程序片断叫作“线程”(Thread),利用它编程的概念就叫作“多线程处理”。多线程处理一个常见的例子就是用户界面。利用线程,用户可按下一个按钮,然后程序会立即作出响应,而不是让用户等待程序完成了当前任务以后才开始响应。用多线程的目的就是提高应用程序对事务处理能力,当

Goldxwang的博客 7130

解决TextMeshPro在AB打包中的字体冗余问题:源码修改全记录

本文详细介绍了如何解决TextMeshPro在AB打包中的字体冗余问题,通过源码改造和工程实践优化Unity项目的性能。内容包括资源加载路径重构、AB打包策略优化及运行时加载方案,有效减少包体体积和构建时间,提升内存效率。

weixin_42558257的博客 184

委托调用线程

//创建一个委托 static Action test1 = delegate () { Console.WriteLine("委托调用线程"); }; static void Main(string[] args) { test1.BeginInvoke(null, null); Console.ReadKey(); }

chinayu2007的专栏 202

Python爬虫实战:5分钟搞定政府网站公开数据抓取(附完整代码)

本文详细介绍了如何使用Python爬虫快速抓取政府网站公开数据,包括环境配置、网站结构分析、请求头构建、数据处理与存储等关键步骤。通过实战案例和完整代码,帮助开发者高效获取结构化数据,适用于数据分析、市场研究等场景。

weixin_29057065的博客 941

用SPSS做信效度分析

对问卷进行Cronbach’s Alpha信度检验。如果此值高于0.8,则说明信度高;如果此值介于0.7-0.8之间,则说明信度较好;如果此值介于0.6~0.7,则说明信度可接受;如果此值小于0.6,说明信度不佳。下面利用SPSS进行分析,点击分析–标度–可靠性分析选项,选中所要分析的问卷数据或题目。得到结果,我们要看这个有用的结果,当克隆巴赫Alpha系数(也可以看标准化后的)大于0.8时候,说明问卷信度较高。

小高~的博客 1万+

线程与委托

线程 线程是程序中独立的指令流。使用 C#编写任何程序时,都有一个入口点:Main()方法。程序从 Main()方 法的第一条语句开始执行,直到这个方法返回为止。 这种程序结构非常适合于其中有一个可识别的任务序列的程序,但程序常常需要同时完成多个 任务。线程对客户端和服务器端应用程序都非常重要。在 Visual Studio编辑器中输入 C#代码 时,系 统会分析代码,用下划线标出遗漏的分号或其他语法错误,这用一个后台线程完成。McrosoftWord 程、任务和同步 ! I 第Ⅲ部分 基 础 的拼写检查

L691321的博客 702

别再只盯着ADC了!手把手教你拆解HLW8032模块的隔离与非隔离采样电路(附BOM清单)

本文深入解析HLW8032模块的隔离与非隔离采样电路设计,提供工程化决策指南。从安全间距到PCB布局,再到误差分析和BOM清单优化,手把手教你避开常见陷阱,确保产品级设计的可靠性和精度。附实用校准策略和关键元器件选型建议,助力硬件开发者提升设计水平。

weixin_29206669的博客 402

c#编程之委托、事件与线程

c#编程之委托、事件与线程委托(delegate)事件(event)线程综合实例 委托(delegate) 委托是一个类,它定义了方法的类型,使得可以将方法当作另一个方法的参数来进行传递,这种将方法动态地赋给参数的做法,可以避免在程序中大量使用If-Else(Switch)语句,同时使得程序具有更好的可扩展性。 在C#中使用delegate关键字定义委托,然后使用我们熟悉的函数调用的语法来调用委托...

weixin_44151489的博客 1594

Google Earth Engine:计算逐年全球潜在蒸发量(PET)的 ERA 数据

通过获取温度、湿度和降水数据,并使用Penman-Monteith公式,我们可以得到每年的潜在蒸发量。在本文中,我们将使用Google Earth Engine平台和ERA(欧洲再分析气象数据集)数据来计算逐年全球的潜在蒸发量(PET)。接下来,我们需要对ERA数据进行预处理,以获取我们需要的潜在蒸发量数据。有了温度、湿度和降水数据,我们可以使用Penman-Monteith公式来计算每年的潜在蒸发量。最后,我们可以将计算得到的潜在蒸发量数据进行可视化,以便更好地理解全球的水汽蒸发情况。

VwajAlgorithm的博客 730

ASP.NET Core 6 Web API在IIS上的部署与调试

通过以上步骤和配置,你应该能够成功部署并调试你的ASP.NET Core 6 Web API在IIS上。记住,权限和配置是关键,确保你的环境和应用程序代码都正确设置。希望这篇博客对你部署和解决IIS上的问题有所帮助。

m0_74337424的博客 522

多线程操作之异步委托

在应届生找工作的时候,多线程操作几乎是所有的公司都会问及的一个基本问题。   这里做了一个多线程操作的总结,这里总结了通过异步委托来实现多线程操作。   定义一个委托,是创建一个线程的最简单的方法,并且异步调用它。委托是方法的类型安全的引用。同时委托还智齿异步调用方法。 委托使用线程池来完成异步任务。 当自己的程序使用异步委托的时候,委托会自动创建ige执行线程的任务。委托使用线程池完

Work Hard, Play Harder! 2014

拼多多小球直径轨迹重合验证码识别

本文分析了拼多多新型验证码的实现原理与破解思路。该验证码采用Canvas绘制小球弹跳轨迹验证,主要难点在于参数还原和轨迹计算。作者通过逆向工程提取了包括弹跳段数、振幅、旋转参数等关键配置(存储在config.json),并利用Python成功模拟了验证过程。核心算法将滑块值映射为0-1区间,通过三次变换计算小球位置,最终采用斜率截距最小值比对完成验证。整个过程分为静态初始化、核心计算和动态渲染三个阶段,其中干扰元素不影响核心验证逻辑。该研究仅用于技术学习,强调严禁任何违法行为。

码王吴彦祖的博客 1329

C# 委托与线程通信

1、C#中的委托机制我简单理解为C++中的函数指针。 用法如下: 使用委托: public delegate string MessageDelegate(string message); public class M { public string T(string message) { return message; } } class...

Ck_Max的博客 860

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

C# 委托&线程的见解(上)—— 委托

对于委托,我们都知道他是一个引用类型,具有引用类型所具有的通性。委托就相当于叫人帮忙,让它帮你做一些事情。 委托一般包含三个方法,分别是BeginInvoke、EndInvoke、Invoke。EndInvoke就不必说了,一看就知道是干嘛的。Invoke 和BeginInvoke,前一个是同步委托,后一个是异步委托,那么何为同步,何为异步呢?看完这篇文章,你可能就会有所了解。 知识无极限,与你来相见,欢迎点赞支持!

yzh的博客 8214

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

java线程委托_多线程和异步委托基础详解

在讲多线程前。先回忆下异步委托:/*异步委托自我解释:即用.net委托来自动创建次线程(子线程)以处理异步方法的调用* 当调用BeginInvoke()方法的时候,程序就会自动创建一个子线程去处理异步委托的方法。*///线程被定义为可执行应用程序中的基本执行单元1 //1:System.Threading 命名空间包含多种类型,可以使用它们来创建多线程应用程序,Thread类是核心,它代表了某个...

weixin_28778267的博客 493

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

线程学习1——异步委托

一.为什么使用线程    简单来讲,就是用线程来实现,在程序运行过程中,还可以同时执行其他操作。二.线程的概述    线程是程序中独立的指令流。使用C#编写任何程序时,都有一个入口:Main()方法。程序从Main()方法的第一条语句开始执行,直到这个方法返回为止。    在.net framework class library中,所有与多线程机制应用相关的类都是放在System

songziling的专栏 531

线程安全性的委托

由于CountingFactorizer的状态就是AtomicLong的状态,而AtomicLong 是线程安全的,因此CountingFactorizer不会对counter的状态施加额外的有效性约束,所以很容易知道CountingFactorizer 是线程安全的。在使用监视器模式的车辆追踪器中返回的是车辆位置的快照,而在使用委托的车辆追踪器中返回的是一个不可修改但却实时的车辆位置视图。(这或许不是个好主意,因为发布可变的变量将对下一步的开发和派生子类带来限制,但不会破坏类的线程安全性。

2301_78008478的博客 783

C#如何回到主线程,如何在委托指定线程执行

SynchronizationContext.Current 为获取当前线程的同步上下文,通过调用Send(同步)和Post (异步)将消息分派到同步上下文,以此实现在指定线程执行!!! this.Invoke为当拥有此控件的基础窗口句柄的线程上执行指定的委托。通过传递此委托,可以在类库里面调用,以此达到在多线程情况下,依然可以随时在主线程里执行委托 Synchronizatio...

qq_38613453的博客 4325

C#委托、事件、线程

这是几个简单的例子,但是实际的开发中委托还还只在反射时用到过,事件的话只自己做了一次,并且还是特意去用的 ,实际上可以不用。线程的话,因为需要,所以用的会多点,这里主要是WS上的线程。 委托 在前面的反射实例中,也有用到委托执行方法。 这个例子是将一个方法或者委托实例作为另外一个函数的入参传递。 至于有什么用,我现在还没用上。 private delegate void Dosth(s...

刘欢的博客 463

委托和线程

一:线程 在.net中提供了两种启动线程的方式,一种是不带参数的启动方式,另一种是带参数的启动的方式。 不带参数的启动方式  如果启动参数时无需其它额外的信息,可以使用ThreadStart来实例化Thread:  带参数的启动方法 带参数,就不能用ThreadStart委托作为构造函数的参数来实例化Thread了,而要 ParameterizedThreadStart委托,和Thr

sunho89的专栏 892
上一篇: webservice and js
下一篇: 反射机制
wfdoublext
博客等级 码龄19年 5粉丝 63原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值