我来回答你的这个问题 异步是C++语言中一个很重要的操作 也是一个比较基础的知识点,希望我的回答对你有用!
实现异步编程有4种方法可供选择,这4种访求实际上也对应着4种异步调用的模式,分为“等待”和“回调”两大类。
一、使用EndInvoke;
二、使用WaitHanle;
三、轮询;
四、回调。
1.使用EndInvoke
当使用BeginInvoke异步调用方法时,如果方法未执行完,EndInvoke方法就会一直阻塞,直到被调用的方法执行完毕,
如下面的代码:
Ellic's Code
1 using System;
2 using System.Threading;
3 namespace MetadataSample
4 {
5 class Program
6 {
7 //声明一个委托类型
8 public delegate void PrintDelegate(string content);
9 public static void Main(string[] args)
10 {
11 int threadId = Thread.CurrentThread.ManagedThreadId;
12 PrintDelegate printDelegate = Program.Print;
13 Console.WriteLine("[主线程id:{0}]\t开始调用打印方法...",threadId);
14 IAsyncResult result = printDelegate.BeginInvoke("Hello world",null,null);
15 printDelegate.EndInvoke(result);
16
17 Console.Write("Press any key to continue . . . ");
18 Console.ReadKey(true);
19 }
20 public static void Print(string content)
21 {
22 int threadId=Thread.CurrentThread.ManagedThreadId;
23 Console.WriteLine("[当前线程id:{0}]\t{1}",threadId,content);
24 System.Threading.Thread.Sleep(2000);
25 Console.WriteLine("[当前线程id:{0}]\t打印方法调用完毕.",threadId);
26 }
27 }
28 }
2.使用WaitHandle
WainHandle类型的WaitOne方法,WaitOne方法有5个重载:
n bool WaitOne()
n bool WaitOne(int millisecondsTimeout)
n bool WaitOne(TimeSpan timeout)
n bool WaitOne(int millisecondsTimeout, bool exitContext)
n bool WaitOne(TimeSpan timeout,bool exitContext)
其中,第一个不带参数的重载相当于WaitOne(-1,false),
第一个参数表示等待的毫秒数,-1表示无限期等待,
第二个参数表示在等待前是否退出上下文的同步域,
并在稍后进行重新获取,是则为TRUE,否则为FALSE。
3.轮询
之前提到的两种方法,只能等下异步方法执行完毕,在完毕之前没有任何提示信息,整个程序就像没有响应一样,用户体验不好,可以通过检查IasyncResult类型的IsCompleted属性来检查异步调用是否完成,如果没有完成,则可以适时地显示一些提示信息,如下面的代码:
Ellic's Code
1 using System;
2 using System.Threading;
3 namespace MetadataSample
4 {
5 class Program
6 {
7 //声明一个委托类型
8 public delegate void PrintDelegate(string content);
9 public static void Main(string[] args)
10 {
11 int threadId = Thread.CurrentThread.ManagedThreadId;
12 PrintDelegate printDelegate = Program.Print;
13 Console.WriteLine("[主线程id:{0}]\t开始调用打印方法...",threadId);
14 IAsyncResult result = printDelegate.BeginInvoke("Hello world",null,null);
15 while (!result.IsCompleted)
16 {
17 Console.WriteLine(" . ");
18 Thread.Sleep(500);
19 }
20 Console.Write("Press any key to continue . . . ");
21 Console.ReadKey(true);
22 }
23 public static void Print(string content)
24 {
25 int threadId=Thread.CurrentThread.ManagedThreadId;
26 Console.WriteLine("[当前线程id:{0}]\t{1}",threadId,content);
27 System.Threading.Thread.Sleep(2000);
28 Console.WriteLine("[当前线程id:{0}]\t打印方法调用完毕.",threadId);
29 }
30 }
31 }
4.回调
之前三种方法者在等待异步方法执行完毕后才能拿到执行的结果,期间主线程均处于等待状态。回调和它们最大的区别是,在调用BeginInvoke时只要提供了回调方法,那么主线程就不必要再等待异步线程工作完毕,异步线程在工作结束后会主动调用我们提供的回调方法,并在回调方法中做相应的处理,例如显示异步调用的结果。
先看到之前那段调用BeginInvoke的代码:
IAsyncResult result = printDelegate.BeginInvoke("Hello world",null,null);
其中,第1个参数是委托签名中的参数,后面2个参数实际是我们在回调方法中要用到的,它们分别是:
AsyncCallback callback
object @object
前者就是回调方法,它要求回调方法的签名必须符合以下条件:
返回类型为void;
参数列表只有1个参数,且为IAsyncResult 类型。
如:void callbackMethod(IasyncResult asyncResult)
回调方法代码如下:
Ellic's Code
1 using System;
2 using System.Threading;
3 namespace MetadataSample
4 {
5 class Program
6 {
7 //声明一个委托类型
8 public delegate void PrintDelegate(string content);
9 public static void Main(string[] args)
10 {
11 int threadId = Thread.CurrentThread.ManagedThreadId;
12 PrintDelegate printDelegate = Program.Print;
13 Console.WriteLine("[主线程id:{0}]\t开始调用打印方法...",threadId);
14 IAsyncResult result = printDelegate.BeginInvoke("Hello world",PrintComplete,printDelegate);
15 Thread.Sleep(10000);
16
17 Console.Write("Press any key to continue . . . ");
18 Console.ReadKey(true);
19 }
20 public static void Print(string content)
21 {
22 int threadId=Thread.CurrentThread.ManagedThreadId;
23 Console.WriteLine("[当前线程id:{0}]\t{1}",threadId,content);
24 System.Threading.Thread.Sleep(1000);
25
26 }
27
28 private static void PrintComplete(IAsyncResult asyncResult)
29 {
30 if(null == asyncResult)
31 {
32 throw new ArgumentNullException();
33 }
34 int threadId = Thread.CurrentThread.ManagedThreadId;
35 (asyncResult.AsyncState as PrintDelegate).EndInvoke(asyncResult);
36 Console.WriteLine("[当前线程id:{0}]\t打印方法调用完毕.",threadId);
37 }
38 }
39 } |