本文是转载,原文地址:http://www.itpub.net/thread-1021075-1-1.html

几个关键词:IAsyncResult,isComplete,asyncResult.AsyncWaitHandle.WaitOne(100, false),asyncResult.AsyncState

开发语言:C#3.0 IDE:Visual Studio 2008 本系列教程主要包括如下内容:
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(int n);

private int method(int n)

{

  Thread.Sleep(n);

  return 100;

}

private void MethodCompleted(IAsyncResult asyncResult)

{

   if (asyncResult == null) return;

   int i =(asyncResult.AsyncState //获取用户当前传入的对象__一个委托“类型”

      as     MyMethod).EndInvoke(asyncResult);

  Console.WriteLine(i);

}
private void Main(object sender, EventArgs e)

{
      MyMethod my = method;

  IAsyncResult asyncResult = my.BeginInvoke(10000,MethodCompleted, my);

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

七、其他组件的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);

}

转载于:https://www.cnblogs.com/xyang/archive/2011/12/14/2287298.html

C#线程系列讲座(1):BeginInvoke和EndInvoke方法相关推荐

  1. C#线程系列讲座(4):同步与死锁

    本文为原创,如需转载,请注明作者和出处,谢谢! 上一篇:C#线程系列讲座(3):线程池和文件下载服务器   虽然线程可以在一定程度上提高程序运行的效率,但也会产生一些副作用.让我们先看看如下的代码: ...

  2. Invoke and BeginInvoke BeginInvoke和EndInvoke方法 (转)

      http://www.cnblogs.com/renhaojie/archive/2009/09/10/1564052.html http://www.cnblogs.com/worldreaso ...

  3. BeginInvoke与EndInvoke方法解决多线程接收委托返回值问题

    BeginInvoke与EndInvoke方法解决多线程接收委托返回值问题 参考文章: (1)BeginInvoke与EndInvoke方法解决多线程接收委托返回值问题 (2)https://www. ...

  4. 异步使用委托delegate --- BeginInvoke和EndInvoke方法

    当我们定义一个委托的时候,一般语言运行时会自动帮委托定义BeginInvoke 和 EndInvoke两个方法,这两个方法的作用是可以异步调用委托. 方法BeginInvoke有两个参数: Async ...

  5. Invoke and BeginInvoke BeginInvoke和EndInvoke方法 (转)2

    七.其他组件的BeginXXX和EndXXX方法 在其他的.net组件中也有类似BeginInvoke和EndInvoke的方法,如System.Net.HttpWebRequest类的BeginGe ...

  6. C#线程系列讲座(3):线程池和文件下载服务器

    如果设计一个服务器程序,每当处理用户请求时,都开始一个线程,将会在一定程序上消耗服务器的资源.为此,一个最好的解决方法就是在服务器启动之前,事先创建一些线程对象,然后,当处理客户端请求时,就从这些建好 ...

  7. C#线程系列讲座(5):同步技术之Monitor

    在上一讲介绍了使用lock来实现线程之间的同步.实际上,这个lock是C#的一个障眼法,在C#编译器编译lock语句时,将其编译成了调用Monitor类.先看看下面的C#源代码: public sta ...

  8. Invoke and BeginInvoke BeginInvoke和EndInvoke方法 (转)3

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

  9. C# BeginInvoke和EndInvoke方法

    http://www.csharpwin.com/csharpspace/11948r7265.shtml 转载于:https://www.cnblogs.com/luciakally/p/48493 ...

最新文章

  1. Digital Image Processing 学习笔记3
  2. 【转】JCR期刊分区及其检索方法
  3. android 判断时间是否过期_眉笔眉粉有保质期吗?怎么判断眉笔眉粉是否过期?...
  4. linux杀sqlplus进程,sqlplus / as sysdba 在linux系统所发起进程
  5. vc mysql封装类_Oracle OCI API封装类VC数据库源码下载-华软网
  6. 云计算是怎样入侵统一通信领域的
  7. 护理方面关于人工智能的构想_如何提出惊人的AI,ML或数据科学项目构想。
  8. 原子设计_您需要了解的有关原子设计的4件事
  9. 显示和快速隐藏Mac桌面所有图标
  10. winxp上传文件到服务器,通过SQLServer的xp_cmdshell在服务器之间传送文件
  11. if...elif...else...fi和case...esac的脚本条件判断式
  12. 跟着动画学习 TCP 三次握手和四次挥手
  13. LOCK - 明确地锁定一个表
  14. 网格自适应_网格自适应的 2 种方法——实现更高效的计算
  15. 安装Visio2010 64bit时提示不能安装32位版本的Office 2010 ,因为您当前已经安装了64位Office产品的解决方法(亲测可行)
  16. 如何使用计算机蠕虫病毒软件,计算机中了蠕虫病毒如何解决
  17. linux 禁用超线程,Linux动态启用/禁用超线程技术
  18. 采用计算机教学的优点,小学计算机教学的特点与重点
  19. eclipse的安装及最大子数组求和
  20. Vue-Router给当前url添加参数时报错 Navigation Duplicated Avoided redundant navigation to current location

热门文章

  1. Winform开发框架之系统重新登录、自动登录实现
  2. 几个软件研发团队管理的小问题
  3. Apache配置代理服务器的方法(1)
  4. Windows or Linux
  5. initBuilder注解接收多个对象
  6. mysql数据库-主主配置
  7. 如何用工匠精神突破创新?
  8. 《Arduino开发实战指南:机器人卷》一2.1 数字I/O口的操作函数
  9. 《精通Wireshark》—第2章2.6节总结
  10. Quaternion.identity是什么意思?