另一种将线程并入应用程序的方法-委托
2012-04-28 16:18 yezhi 阅读(641) 评论(2) 编辑 收藏 举报委托的同步
声明一个委托:
public delegate int BinaryOp(int x, int y);
BinaryOp编译后,其所属程序集将包含一个根据委托声明动态生成的类的定义,将会生成如下三个方法:
| | |___[MET] BeginInvoke : class [mscorlib]System.IAsyncResult(int32,int32,class [mscorlib]System.AsyncCallback,object) | | |___[MET] EndInvoke : int32(class [mscorlib]System.IAsyncResult) | | |___[MET] Invoke : int32(int32,int32)
Invoke()方法用来调用被代理对象以同步方式维护的方法。因此,调用委托的线程(比如应用程序的主线程)将会一直等待,直到委托调用完成。
BeginInvoke()用于异步调用方法。
EndInvoke()用于获取被调用方法的返回值。后两个方法在后面异步调用方法中谈到。
看则小例:
public delegate int BinaryOp(int x, int y); class Program { static void Main(string[] args) { Console.WriteLine("***** 同步方式 *****"); Console.WriteLine("线程标识{0}.", Thread.CurrentThread.ManagedThreadId); //同步模式下调用Add() BinaryOp b = new BinaryOp(Add); //也可写成b.Invoke(10, 10); int answer = b(10, 10); //直到b(10, 10) Add()方法完成后,这行代码才会执行 Console.WriteLine("Add()方法完成了!"); Thread.Sleep(3000); Console.WriteLine("10 + 10 = {0}.", answer); Console.ReadLine(); } static int Add(int x, int y) { Console.WriteLine("线程标识{0}.", Thread.CurrentThread.ManagedThreadId); //模拟耗时 Thread.Sleep(5000); return x + y; } }
输出结果:
异步调用方法
小例:
public delegate int BinaryOp(int x, int y); class Program { static void Main(string[] args) { Console.WriteLine("***** 异步方式 *****"); Console.WriteLine("线程标识{0}.", Thread.CurrentThread.ManagedThreadId); //次线程下调用Add() BinaryOp b = new BinaryOp(Add); IAsyncResult iAR = b.BeginInvoke(10, 10, null, null); //不用等待Add()方法完成 Console.WriteLine("Add()方法正在执行中……,这里可以在主线程做下其它的事情。"); int answer = b.EndInvoke(iAR); Console.WriteLine("Add()已完成,10 + 10 = {0}.", answer); Console.WriteLine("以上可以看到,两个不同的线程ID,说明是两个线程在运行"); Console.ReadLine(); } static int Add(int x, int y) { Console.WriteLine("线程标识{0}.", Thread.CurrentThread.ManagedThreadId); //模拟耗时 Thread.Sleep(5000); return x + y; } }
输出结果:
同步调用线程,通过IAsyncResult接口提供的Iscompleted属性来判断异步调用是否完成
小例:
public delegate int BinaryOp(int x, int y); class Program { static void Main(string[] args) { Console.WriteLine("***** 异步方式 *****"); Console.WriteLine("线程标识{0}.", Thread.CurrentThread.ManagedThreadId); //次线程下调用Add() BinaryOp b = new BinaryOp(Add); IAsyncResult iAR = b.BeginInvoke(10, 10, null, null); //当次线程还未完成时,在主线程可以做些事情 //可使用IsCompleted属性判断实现一种同步 while (!iAR.IsCompleted) { Console.WriteLine("你完成了吗?这里可以在主线程做下其它的事情。"); Thread.Sleep(1000); } int answer = b.EndInvoke(iAR); Console.WriteLine("完成啦,10 + 10 = {0}.", answer); Console.ReadLine(); } static int Add(int x, int y) { Console.WriteLine("线程标识{0}.", Thread.CurrentThread.ManagedThreadId); //模拟耗时 Thread.Sleep(5000); return x + y; } }
输出结果:
AsyncCallback委托
虽然IAsyncResult的这些属性提供了同步调用线程的方式,不过不是最高效的,也让人蛋疼,不停的问你“完成了吗?”,
不通过轮询一个委托来确定异步调用方法执行是否结束,而是在任务完成时由次线程主动通知调用线程的方式,这样更好。
实现这种方式,需要调用BeginInvoke()时的提供的一个System.AsyncCallback委托的实例作为参数。
当异步调用完成时,委托便会自动调用(AsyncCallback对象)指定的方法。
小例:
public delegate int BinaryOp(int x, int y); class Program { private static bool isDone = false; static void Main(string[] args) { Console.WriteLine("***** 异步方式 *****"); Console.WriteLine("线程标识{0}.", Thread.CurrentThread.ManagedThreadId); //次线程下调用Add() BinaryOp b = new BinaryOp(Add); IAsyncResult iAR = b.BeginInvoke(10, 10, new AsyncCallback(AddComplete), null); while (!isDone) { Thread.Sleep(1000); Console.WriteLine("次线程工作中……"); } Console.ReadLine(); } static int Add(int x, int y) { Console.WriteLine("线程标识{0}.", Thread.CurrentThread.ManagedThreadId); //模拟耗时 Thread.Sleep(5000); return x + y; } static void AddComplete(IAsyncResult iAR) { Console.WriteLine("线程标识{0}.", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("Add()方法已完成了。"); //因为这里访问不到BinaryOp委托,所有先获取BinaryOp委托对象 AsyncResult ar = (AsyncResult)iAR; BinaryOp b = ar.AsyncDelegate as BinaryOp; Console.WriteLine("10 + 10 = {0}.", b.EndInvoke(iAR)); isDone = true; } }
输出结果:
传递和接收自定义状态的数据
异步委托最后一个关注的地方是BeginInvoke()方法的最后一个参数,该参数允许主线程传递额外的状态信息给回调方法。
因为这个参数类型是object类型,所有可以传入任何类型的数据。
小例:
public delegate int BinaryOp(int x, int y); class Program { private static bool isDone = false; static void Main(string[] args) { Console.WriteLine("***** 异步方式 *****"); Console.WriteLine("线程标识{0}.", Thread.CurrentThread.ManagedThreadId); //次线程下调用Add() BinaryOp b = new BinaryOp(Add); IAsyncResult iAR = b.BeginInvoke(10, 10, new AsyncCallback(AddComplete), "2 这是从主线程自定义传进来的参数"); while (!isDone) { Thread.Sleep(1000); Console.WriteLine("次线程工作中……"); } Console.ReadLine(); } static int Add(int x, int y) { Console.WriteLine("线程标识{0}.", Thread.CurrentThread.ManagedThreadId); //模拟耗时 Thread.Sleep(5000); return x + y; } static void AddComplete(IAsyncResult iAR) { Console.WriteLine("线程标识{0}.", Thread.CurrentThread.ManagedThreadId); Console.WriteLine("Add()方法已完成了。"); //因为这里访问不到BinaryOp委托,所有先获取BinaryOp委托对象 //AsyncResult ar = (AsyncResult)iAR; //BinaryOp b = ar.AsyncDelegate as BinaryOp; //iar.AsyncState这里将实现强制转换,所以主线程和次线程必段认同由AsyncState返回的实际类型 Console.WriteLine("10 + 10 = {0}.", iAR.AsyncState.ToString()); isDone = true; } }
输出结果: