WinForm 异步调用方法

摘要:
如果要在线程中异步执行方法,请首先创建该方法的委托类型,然后CLR将自动为委托类型定义BeginInvoke方法和EndInvoke方法。我们依赖这两个方法异步调用委托类型指向BeginInvoke的方法,该方法用于启动异步调用。此方法与异步执行的方法具有相同的参数列表,只添加了两个参数。后面将描述两个附加参数的功能。执行BeginInvoke方法后,将立即返回IAsyncResult以监视所调用方法的执行进度。

假如要在一个线程中异步执行一个方法,则先创建一个该方法的委托类型,然后CLR会自动为该委托类型定义一个BeginInvoke方法和EndInvoke方法,我们就靠这两个方法异步调用委托类型指向的方法(这句话有点绕口,呵呵)

BeginInvoke这个方法用于启动异步调用,该方法具有和要异步执行的方法具有相同的参数列表,只不过又多加了两个参数,多加的那两个参数的作用在后面介绍。执行BeginInvoke方法后,将立即返回一个IAsyncResult,用于监视被调用方法执行的进度。

EndInvoke这个方法用于得到异步调用的结果,调用BeginInvoke方法后随时可以调用EndInvoke方法,假如异步调用还没有完成,EndInvoke会阻塞到异步调用执行完毕,EndInvoke的参数包括被调用方法的out和ref参数,还有在调用BeginInvoke方法时得到的那个IAsyncResult(好像就是一个哈希表的key,可以靠这个key去得到相应的线程,这样就可以处理多线程而不至于混乱了)

第一种方法:使用BeginInvoke方法后,主线程去执行一些操作,然后再使用EndInvoke方法等待被调用方法完成,以下是示例代码

 

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace sample
{
  class AsyncDemo // 我定义了一个演示的类,里面有一个测试方法TestMethod 其实完全可以把这个TestMethod写到Main()函数的同一个类中,只不过写成static方法即可
  {
    public string TestMethod(int callDuration, out int threadid)
    {
        Console.WriteLine("Test Method begins");
        Thread.Sleep(callDuration);//睡眠callDuration指定的毫秒
        threadid = AppDomain.GetCurrentThreadId();//获取当前线程的id
        return "MyCallTime was" + callDuration.ToString();//返回当前线程睡眠的时间

    }
  }
  public delegate string AsyncDelegate(int callDuration, out int threadid); //创建一个AsyncDemo类中TestMethod方法相同签名的委托类型

  class Program
  {
    static void Main(string[] args)
    {
        int threadID;
        AsyncDemo ad = new AsyncDemo();//声明一个AsyncDemo类型的对象ad,并创建一个实例赋给它
        AsyncDelegate andl = new AsyncDelegate(ad.TestMethod);//声明一个AsyncDelegate类型的对象andl,并让他指向ad对象的TestMethod方法
        IAsyncResult ar = andl.BeginInvoke(3000, out threadID, null, null);//执行andl的BeginInvoke方法,返回一个IAsyncResult类型的实例对象给ar变量,其实是一个号码牌(不知道这样说是否形象)
        Thread.Sleep(10);//使当前线程睡眠10毫秒(其实可去掉这句,我写这个的目的是确保异步线程已启动,再执行以下语句)
        Console.WriteLine("Main Thread {0} Does Some Work",
          AppDomain.GetCurrentThreadId());//输出当前线程的id
        string ret = andl.EndInvoke(out threadID, ar);//使用EndInvoke方法,传入out或ref类型参数和在调用BeginInvoke方法时得到的IAsyncResult,此时主线程将等待异步调用执行完毕,返回结果后执行以下语句
        Console.WriteLine("The call executed on thread {0},with return value : {1}",
          threadID, ret);
        Console.ReadLine();
    }
  }
}


ok,以上是第一种直接使用EndInvoke来等待异步调用完成的方法 
================================================
================================================

第二种方法是借助返回的IAsyncHandle的WaitHandle属性的WaitOne()方法实现线程同步后,执行代码,然后将要执行的代码执行后随时可调用EndInvoke方法。

示例代码基本没有什么改动,只是在BeginInvoke方法后执行一个ar.WaitHandle.WaitOne()方法,该方法将阻塞主线程使主线程等待返回ar的begininvoke调用的方法的线程执行完毕(不要怪我说话有点绕,我是说的详细,否则你弄不明白,仔细看这句话就明白了^o^)。

本着一切代码都是纸老虎的原则,请仔细分析下面的代码 其实和示例1基本无异 ,只是使用WaitOne()方法同步了一下线程而已

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace sample
{
  class AsyncDemo
  {
    public string TestMethod(int callDuration, out int threadid)
    {
        Console.WriteLine("Test Method begins");
        Thread.Sleep(callDuration);
        threadid = AppDomain.GetCurrentThreadId();
        return "MyCallTime was" + callDuration.ToString();
    }
  }
  public delegate string AsyncDelegate(int callDuration, out int threadid);
  class Program
  {
    static void Main(string[] args)
    {
        int threadID;
        AsyncDemo ad = new AsyncDemo();
        AsyncDelegate andl = new AsyncDelegate(ad.TestMethod);
        IAsyncResult ar = andl.BeginInvoke(3000, out threadID, null, null);
        Thread.Sleep(10);
        Console.WriteLine("Main Thread {0} Does Some Work",
          AppDomain.GetCurrentThreadId());
        ar.AsyncWaitHandle.WaitOne();//执行该方法时主线程将等待辅助线程执行完毕,使两线程同步后再执行以下语句
        Console.WriteLine("其实很简单");//执行一些方法
        string ret = andl.EndInvoke(out threadID, ar);//使用EndInvoke来获取返回结果和传入ref和out的变量获取修改后的实例的位置(这我就不太好用语言来表述了,你自己心领神会吧)
        Console.WriteLine("The call executed on thread {0},with return value : {1}",
          threadID, ret);
        Console.ReadLine();
    }
  }
}

  

 

免责声明:文章转载自《WinForm 异步调用方法》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇vi常用按键etcd v3 ssl 集群添加新节点下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

多核时代,还在使用任务管理器来看程序的性能吗?

是否为了一个程序只占用了13%的CPU利用率而沾沾自喜呢? 别忘了现在是多核时代,四核,超线程的i7. 单个线程最多只能占到12.5%的CPU利用率。 忘记这个简单的CPU利用率吧,多核时代,你需要具体知道到每个线程的利用率。 这篇博客,来源一个刚刚遇到的问题。 背景是我们正在针对Windows Media Player开发一些东西,具体是什么不重要。...

C#winform的textbox怎么设置滚动条

用 C#开发软件的时候文本框textbox是没有滚动条的,而且是单行文本。下面教大家如何设置多行,并且设置横向滚动条和垂直滚动条。 打开VS工具,创建一个winform窗体项目。系统会自动创建一个主窗体。在左边工具栏搜索textbox后,拉到窗体里面。 这个时候你看到一个单行文本框,右击文本框,点击属性,右边会显示文本框的属性窗口。选择MutilLine...

Python基础-多线程与多进程

一,线程与进程之间的关系:(从知乎上看到的) 一个必须知道的事实:执行一段程序代码,实现一个功能的过程介绍 ,当得到CPU的时候,相关的资源必须也已经就位,就是显卡啊,GPS啊什么的必须就位,然后CPU开始执行。这里除了CPU以外所有的就构成了这个程序的执行环境,也就是我们所定义的程序上下文。当这个程序执行完了,或者分配给他的CPU执行时间用完了,那它就...

CAS导致的ABA问题及解决:时间戳原子引用AtomicReference、AtomicStampedReference

1.CAS导致ABA问题: CAS算法实现一个重要前提需要取出内存中某时刻的数据并在当下时刻比较并交换,那么在这个时间差中会导致数据的变化。 比如:线程1从内存位置V中取出A,这时线程2也从V中取出A,线程2进行了一些操作将值改成了B,然后线程2又将V的数据改回A;此时线程1进行CAS操作发现内存中仍然是A,然后线程1操作成功。 尽管线程1的CAS操作成功...

[C#] 多线程总结(结合进度条)

(一)使用线程的理由 1、可以使用线程将代码同其他代码隔离,提高应用程序的可靠性。 2、可以使用线程来简化编码。 3、可以使用线程来实现并发执行。 (二)基本知识 1、进程与线程:进程作为操作系统执行程序的基本单位,拥有应用程序的资源,进程包含线程,进程的资源被线程共享,线程不拥有资源。 2、前台线程和后台线程:通过Thread类新建线程默认为前台线程。当...

dump解析入门-用VS解析dump文件进行排障

突然有一天部署在服务器的一个应用挂掉了,没办法只能进入服务器打开 【事件查看器】查看下,好不容易找到了打开后一脸懵逼 事件查看器查到的内容根本对我们排障没有任何作用。 在这个时候如果有对应的dump文件就能派上用场了, 只要有dump文件就能查到应用挂掉那刻的一手情报,可能有人认为分析dump文件是非常难的事情, 但是最近不断有新的dump分析工具出来...