多线程之异步编程模式
.Net为执行异步操作提供了三中模式:
- 异步编程模型 (APM)
- 基于事件的异步模式(EAP)
- 基于任务的异步模式(TAP)
1.异步编程模型(APM)。
使用IAsyncResult设计模式的异步操作通过Begin操作和End操作两个方法实现。
在调用Begin操作后,调用线程继续执行指令,同时异步操作在另外一个线程上执行,调用线程调用End方法来获取结果。
Code:
1 namespace Examples 2 { 3 public class Progrom 4 { 5 public static void Main() 6 { 7 AsyncWorkTest work = new AsyncWorkTest(); 8 IAsyncResult result = work.BeginWork(CallBack, null); 9 Console.WriteLine("Work is begining..."); 10 string ret = work.EndWork(result); 11 Console.WriteLine(ret); 12 Console.WriteLine("Work is end..."); 13 Console.ReadKey(); 14 } 15 16 static void CallBack(object obj) 17 { 18 //do someing 19 } 20 } 21 22 public class AsyncResult : IAsyncResult 23 { 24 public AsyncResult() 25 { 26 //Accept parameters 27 } 28 private object asyncState; 29 private volatile bool isCompleted; 30 private volatile bool completedSynchronously; 31 private ManualResetEvent asynWaitHandle; 32 33 public string Result = "Mandel"; 34 35 public object AsyncState 36 { 37 get { return asyncState; } 38 } 39 public WaitHandle AsyncWaitHandle 40 { 41 get 42 { 43 if (this.asynWaitHandle == null) 44 { 45 Interlocked.CompareExchange<ManualResetEvent>(ref this.asynWaitHandle, new ManualResetEvent(false), null); 46 } 47 return asynWaitHandle; 48 } 49 } 50 public bool CompletedSynchronously 51 { 52 get { return completedSynchronously; } 53 } 54 public bool IsCompleted 55 { 56 get { return isCompleted; } 57 } 58 59 public void Work() 60 { 61 //do someing 62 Thread.Sleep(3000); ; 63 Result = "The Silent Southern Girl"; 64 asyncState = this; 65 completedSynchronously = false; 66 isCompleted = true; 67 asynWaitHandle.Set(); 68 } 69 70 } 71 72 public class AsyncWorkTest 73 { 74 public IAsyncResult BeginWork(AsyncCallback callback, object state) 75 { 76 AsyncResult result = new AsyncResult(); 77 ThreadPool.QueueUserWorkItem((action) => 78 { 79 result.Work(); 80 if (callback != null) 81 { 82 callback((AsyncResult)state); 83 } 84 }, state); 85 return result; 86 } 87 88 public string EndWork(IAsyncResult re) 89 { 90 AsyncResult result = (AsyncResult)re; 91 result.AsyncWaitHandle.WaitOne(); 92 return result.Result; 93 } 94 } 95 96 }
如果等待异步操作结果时需要阻塞调用线程,可以使用以下方法:
- 使用AsyncWaitHandle阻止调用线程
- 调用结束异步操作来阻止调用线程(本例子即使用这个)
- 轮询异步操作状态来阻止调用线程。
如果等待异步操作结果时不能阻塞调用线程,可使用以下方法:
- 使用AsyncCallback委托,在委托中结束异步操作。
2.基于事件的异步编程模式(EAP)
基于事件的异步操作模式具有多线程应用程序的优点,同时隐匿了多线程设计中固有的许多问题。使用EAP类讲能够:
- 在后台执行耗时任务,不会中断应用程序
- 可同时执行多个操作,每个操作完成讲会接到通知
- 等待资源变得可用,但不会停止("挂起")您的应用程序
- 使用事件和委托模型与挂起的异步操作进行通信
BackgroundWorker组件是典型的封装好的EAP。
支持基于事件的异步编程模型的类将会提供若干个异步执行方法MethodNameAsync,支持取消异步的方法MethodNameCancelAsync,可以提供进度报告的事件onProgressChanged. 支持异步完成后通知事件onWorkCompleted。
Code:
1 class EAPTest 2 { 3 public static void Main() 4 { 5 Work myWork = new Work(); 6 myWork.onProgressChanged += new ProgressChangedEventHandler(myWork_onProgressChanged); 7 myWork.onWorkCompleted += new WorkCompletedEventHandler(myWork_onWorkCompleted); 8 myWork.WoekAsync("Mandel"); 9 myWork.WoekAsync("Alan"); 10 Thread.Sleep(4000); 11 myWork.CancelAsync("Alan"); 12 Console.ReadKey(); 13 } 14 15 static void myWork_onProgressChanged(WorkProgressChangedEventArgs e) 16 { 17 Console.WriteLine("Worked" + e.TaskID + " " + e.ProgressPercentage.ToString() + "% --------------"); 18 } 19 20 static void myWork_onWorkCompleted(object sender, WorkCompletedEventArgs e) 21 { 22 Console.WriteLine("Work " + e.TaskID + "Completed---------"); 23 } 24 } 25 26 //delegate 27 public delegate void ProgressChangedEventHandler(WorkProgressChangedEventArgs e); 28 public delegate void WorkCompletedEventHandler(object sender, WorkCompletedEventArgs e); 29 class Work 30 { 31 private delegate void WorkerEventHandler(AsyncOperation asyncOp, object taskID); 32 private delegate void www(); 33 private SendOrPostCallback onProgressReportDelegate; 34 private SendOrPostCallback onCompletedDelegate; 35 36 public event ProgressChangedEventHandler onProgressChanged; 37 public event WorkCompletedEventHandler onWorkCompleted; 38 39 private HybridDictionary userStateToLifetime = new HybridDictionary(); 40 41 public Work() 42 { 43 onProgressReportDelegate = new SendOrPostCallback(ReportProgress); 44 onCompletedDelegate = new SendOrPostCallback(WorkCompleted); 45 } 46 private void WorkCompleted(object operationState) 47 { 48 WorkCompletedEventArgs e = operationState as WorkCompletedEventArgs; 49 if (onWorkCompleted != null) 50 { 51 onWorkCompleted(this, e); 52 } 53 } 54 private void ReportProgress(object state) 55 { 56 WorkProgressChangedEventArgs e = state as WorkProgressChangedEventArgs; 57 if (onProgressChanged != null) 58 { 59 onProgressChanged(e); 60 } 61 } 62 63 public virtual void WoekAsync(string taskId) 64 { 65 // Create an AsyncOperation for taskId. 66 AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(taskId); 67 lock (userStateToLifetime.SyncRoot) 68 { 69 if (userStateToLifetime.Contains(taskId)) 70 { 71 throw new ArgumentException("Task ID parameter must be unique", "taskId"); 72 } 73 74 userStateToLifetime[taskId] = asyncOp; 75 } 76 // Start the asynchronous operation. 77 WorkerEventHandler workerDelegate = new WorkerEventHandler(Worker); 78 workerDelegate.BeginInvoke(asyncOp, taskId, null, null); 79 } 80 private void Worker(AsyncOperation asyncOp, object taskID) 81 { 82 Exception e = null; 83 ProgressChangedEventArgs progressEventArg; 84 for (int i = 0; i < 5; i++) 85 { 86 Thread.Sleep(1000); 87 Console.WriteLine(i); 88 } 89 if (!TaskCanceled(asyncOp.UserSuppliedState)) 90 { 91 //Do the work 92 try 93 { 94 Console.WriteLine("Come On! " + taskID); 95 Console.WriteLine("Work " + taskID.ToString() + " is working"); 96 progressEventArg = new WorkProgressChangedEventArgs(taskID, 50, new object()); 97 asyncOp.Post(this.onProgressReportDelegate, progressEventArg); 98 Console.WriteLine("Work " + taskID.ToString() + " has been completed"); 99 progressEventArg = new WorkProgressChangedEventArgs(taskID, 100, new object()); 100 asyncOp.Post(this.onProgressReportDelegate, progressEventArg); 101 } 102 catch (Exception ex) 103 { 104 e = ex; 105 } 106 this.CompletionMethod(taskID, e, TaskCanceled(asyncOp.UserSuppliedState), asyncOp); 107 } 108 else 109 { 110 Console.WriteLine("Work " + taskID.ToString() + " has been canceled"); 111 } 112 } 113 114 public void CancelAsync(object taskId) 115 { 116 AsyncOperation asyncOp = userStateToLifetime[taskId] as AsyncOperation; 117 if (asyncOp != null) 118 { 119 lock (userStateToLifetime.SyncRoot) 120 { 121 userStateToLifetime.Remove(taskId); 122 } 123 } 124 } 125 126 private bool TaskCanceled(object taskId) 127 { 128 return (userStateToLifetime[taskId] == null); 129 } 130 131 private void CompletionMethod(object taskID, Exception exception, bool canceled, AsyncOperation asyncOp) 132 { 133 if (!canceled) 134 { 135 lock (userStateToLifetime.SyncRoot) 136 { 137 userStateToLifetime.Remove(asyncOp.UserSuppliedState); 138 } 139 } 140 WorkCompletedEventArgs e = new WorkCompletedEventArgs(taskID.ToString(), exception, canceled, asyncOp.UserSuppliedState); 141 asyncOp.PostOperationCompleted(onCompletedDelegate, e); 142 } 143 } 144 145 //Args 146 public class WorkProgressChangedEventArgs : ProgressChangedEventArgs 147 { 148 private object taskID = null; 149 150 public WorkProgressChangedEventArgs(object value, int progressPercentage, object userToken) 151 : base(progressPercentage, userToken) 152 { 153 this.taskID = value; 154 } 155 /// <summary> 156 /// 任务标识 157 /// </summary> 158 public object TaskID 159 { 160 get 161 { 162 return taskID; 163 } 164 } 165 } 166 public class WorkCompletedEventArgs : AsyncCompletedEventArgs 167 { 168 object taskID = ""; 169 public WorkCompletedEventArgs(object value, Exception e, bool canceled, object state) 170 : base(e, canceled, state) 171 { 172 this.taskID = value; 173 } 174 /// <summary> 175 /// 任务标识 176 /// </summary> 177 public object TaskID 178 { 179 get 180 { 181 RaiseExceptionIfNecessary(); 182 return taskID; 183 } 184 } 185 }