.NET Framework的IAsyncResult接口的细节


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

概述

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

[System.Runtime.InteropServices.ComVisible(true)]
public interface IAsyncResult
{
    object AsyncState { get; }
    WaitHandle AsyncWaitHandle { get; }
    bool CompletedSynchronously { get; }
    bool IsCompleted { get; }
}

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

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

示例程序

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

using System;
using System.Threading; 

namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncDemo 
    {
        // 将要被异步执行的函数
        public string TestMethod(int callDuration, out int threadId) 
        {
            Console.WriteLine("Test method begins.");
            Thread.Sleep(callDuration); // 被异步执行的函数所在的线程休眠callDuration所指定的时间
            threadId = Thread.CurrentThread.ManagedThreadId; // 拿到系统给本异步执行的函数分配的运行线程的id
            return String.Format("My call time was {0}.", callDuration.ToString());
        }
    }

    // 将要被异步执行的函数的签名声明
    public delegate string AsyncMethodCaller(int callDuration, out int threadId);
}

调用AsyncDemo的类如下:

using System;
using System.Threading;
namespace Examples.AdvancedProgramming.AsynchronousOperations
{
    public class AsyncMain 
    {
        static void Main() 
        {
            int threadId;
            AsyncDemo ad = new AsyncDemo();

            // 创建一个delegate,这个delegate指向AsyncDemo.TestMethod方法
            AsyncMethodCaller caller = new AsyncMethodCaller(ad.TestMethod);

            //  这里的BeginInvoke是Delegate的异步调用方法,该方法有以下特性:
            //  a、委托的BeginInvoke方法,在线程池分配的子线程中执行委托
            //  b、委托执行时不会阻塞主线程(调用委托的BeginInvoke线程),主线程继续向下执行。
            //  c、委托执行时会阻塞子线程。
            //  d、委托结束时,如果有返回值,子线程讲返回值传递给主线程;如果有回调函数,子线程
            //     将继续执行回调函数。
            //  参考网页 
            //  https://www.cnblogs.com/EasonLeung/p/3683492.html
            //  https://www.cnblogs.com/markhe/articles/5587956.html
            //  https://www.jb51.net/article/155167.htm

            // 第一个参数就是AsyncMethodCaller函数签名中的int callDuration参数
            // 第二个参数就是AsyncMethodCaller函数签名中的out int threadId参数
            IAsyncResult result = caller.BeginInvoke(3000, out threadId, null, null);

            Thread.Sleep(0);
            Console.WriteLine("Main thread {0} does some work.",Thread.CurrentThread.ManagedThreadId);

            // Wait for the WaitHandle to become signaled.
            // 执行本句代码之后,会阻塞当前运行的线程,直到WaitHanle得到赋值为止
            result.AsyncWaitHandle.WaitOne();

            // 参考网址: https://docs.microsoft.com/zh-cn/dotnet/api/system.threading.waithandle.waitone?view=netframework-3.5#System_Threading_WaitHandle_WaitOne
            // WaitHanle得到赋值之后,本线程可以继续执行下去了,要获取到本次delegate调用的回调值,需要
            // 调用EndInvoke方法
            string returnValue = caller.EndInvoke(out threadId, result);

            // 获取完毕之后,关闭wait handle
            result.AsyncWaitHandle.Close();

            Console.WriteLine("The call executed on thread {0}, with return value \"{1}\".",
                threadId, returnValue);
        }
    }
}

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

  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