.NET Framework的IAsyncResult接口的细节
Table of Contents
请尊重原作者的工作,转载时请务必注明转载自: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预定义的类是继承实现这个接口,如下:
- AsyncResult
- SecurityTokenProvider.SecurityTokenAsyncResult
- AsyncResult
- Task
- 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执行相关的初始化工作Main thread 1 does some work。
- 调用BeginInvoke方法,启动TestMethod该函数,此方法将会在另一个线程3中执行此函数。
- 调用BeginInvoke方法会马上返回一个IAsyncResult类型的返回值,调用该返回值的WaitHandle成员AsyncWaitHandle的WaitOne方法阻塞本线程1直到线程3结束返回为止。
- 线程1恢复后,接下来可以调用EndInvoke方法取到回调值。
- 调用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