.NET Framework的IAsyncResult接口的细节

请尊重原作者的工作,转载时请务必注明转载自:www.xionggf.com

概述

IAsynResult接口用来表征一个异步操作的结果。它的定义声明如下:

1[System.Runtime.InteropServices.ComVisible(true)]
2public interface IAsyncResult
3{
4    object AsyncState { get; }
5    WaitHandle AsyncWaitHandle { get; }
6    bool CompletedSynchronously { get; }
7    bool IsCompleted { get; }
8}

有一些.NET Framework预定义的类是继承实现这个接口,如下:

  1. AsyncResult
  2. SecurityTokenProvider.SecurityTokenAsyncResult
  3. AsyncResult
  4. Task
  5. CommittableTransaction

示例程序

接下来的示例演示了如何使用了IAsyncResult接口中的AsyncWaitHandle属性,去获取到一个WaitHandle类型的值,以及如何使用一个delegate去等待一个异步调用。当异步调用完成后,WaitHandle类型的返回值将会被赋值上。这示例由两个类组成,一个是包含了异步调用函数的类;另一个类则是包含了调用异步函数的方法。

 1using System;
 2using System.Threading; 
 3
 4namespace Examples.AdvancedProgramming.AsynchronousOperations
 5{
 6    public class AsyncDemo 
 7    {
 8        // 将要被异步执行的函数
 9        public string TestMethod(int callDuration, out int threadId) 
10        {
11            Console.WriteLine("Test method begins.");
12            Thread.Sleep(callDuration); // 被异步执行的函数所在的线程休眠callDuration所指定的时间
13            threadId = Thread.CurrentThread.ManagedThreadId; // 拿到系统给本异步执行的函数分配的运行线程的id
14            return String.Format("My call time was {0}.", callDuration.ToString());
15        }
16    }
17
18    // 将要被异步执行的函数的签名声明
19    public delegate string AsyncMethodCaller(int callDuration, out int threadId);
20}

调用AsyncDemo的类如下:

 1using System;
 2using System.Threading;
 3namespace Examples.AdvancedProgramming.AsynchronousOperations
 4{
 5    public class AsyncMain 
 6    {
 7        static void Main() 
 8        {
 9            int threadId;
10            AsyncDemo ad = new AsyncDemo();
11
12            // 创建一个delegate,这个delegate指向AsyncDemo.TestMethod方法
13            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);
14       
15            //  这里的BeginInvoke是Delegate的异步调用方法,该方法有以下特性:
16            //  a、委托的BeginInvoke方法,在线程池分配的子线程中执行委托
17            //  b、委托执行时不会阻塞主线程(调用委托的BeginInvoke线程),主线程继续向下执行。
18            //  c、委托执行时会阻塞子线程。
19            //  d、委托结束时,如果有返回值,子线程讲返回值传递给主线程;如果有回调函数,子线程
20            //     将继续执行回调函数。
21            //  参考网页 
22            //  https://www.cnblogs.com/EasonLeung/p/3683492.html
23            //  https://www.cnblogs.com/markhe/articles/5587956.html
24            //  https://www.jb51.net/article/155167.htm
25
26            // 第一个参数就是AsyncMethodCaller函数签名中的int callDuration参数
27            // 第二个参数就是AsyncMethodCaller函数签名中的out int threadId参数
28            IAsyncResult result = caller.BeginInvoke(3000, out threadId, null, null);
29
30            Thread.Sleep(0);
31            Console.WriteLine("Main thread {0} does some work.",Thread.CurrentThread.ManagedThreadId);
32
33            // Wait for the WaitHandle to become signaled.
34            // 执行本句代码之后,会阻塞当前运行的线程,直到WaitHanle得到赋值为止
35            result.AsyncWaitHandle.WaitOne();
36
37            // 参考网址: https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.waithandle.waitone?view=netframework-3.5#System_Threading_WaitHandle_WaitOne
38            // WaitHanle得到赋值之后,本线程可以继续执行下去了,要获取到本次delegate调用的回调值,需要
39            // 调用EndInvoke方法
40            string returnValue = caller.EndInvoke(out threadId, result);
41
42            // 获取完毕之后,关闭wait handle
43            result.AsyncWaitHandle.Close();
44
45            Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
46                threadId, returnValue);
47        }
48    }
49}

上面的代码执行流程大致是:

  1. 主线程1执行相关的初始化工作Main thread 1 does some work。
  2. 调用BeginInvoke方法,启动TestMethod该函数,此方法将会在另一个线程3中执行此函数。
  3. 调用BeginInvoke方法会马上返回一个IAsyncResult类型的返回值,调用该返回值的WaitHandle成员AsyncWaitHandle的WaitOne方法阻塞本线程1直到线程3结束返回为止。
  4. 线程1恢复后,接下来可以调用EndInvoke方法取到回调值。
  5. 调用IAsyncResult类型的返回值的AsyncWaitHandle成员的Close方法结束操作。

IAsyncResult的属性描述表

属性名 描述
AsyncState 获取一个用户定义的对象,该对象限定或包含有关异步操作的信息。
AsyncWaitHandle 获取用于等待异步操作完成的 WaitHandle。
CompletedSynchronously 获取一个值,该值指示异步操作是否同步完成。
IsCompleted 获取一个值,该值指示异步操作是否已完成。

WaitHandle.WaitOne的一些细节

##参考网页: https://docs.microsoft.com/en-us/dotnet/api/system.iasyncresult?view=netframework-4.8

https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/calling-synchronous-methods-asynchronously?view=netframework-4.8