(1)對於Thread的Abort方法,如果線程當前正在執行的是一段非托管代碼,那麼CLR就不會拋出ThreadAbortException,只有當代碼繼續回到CLR中時,才會引發ThreadAbortException。當然,即便是在CLR環境中ThreadAbortException也不會立即引發。
(2)對於BackgroundWorker的CancelAsync方法,需要設置WorkerSupportsCancellation屬性為True,在執行方法內部檢測CancellationPending標識,用戶負責退出。
(3)對於CancellationTokenSource,場景主要為對任務設置一個預期執行時間,對超時的任務自動取消。達到時間間隔後自動觸發Cancel方法,IsCancellationRequested被設置為True,用戶同樣需要在方法內部檢測IsCancellationRequested屬性。
本文在基於上述基礎上,對於方法的Retry(重新執行)操作,執行時間可能比較久,容易導致主線程阻塞,因此主要以BackgroundWorker來執行相關操作。RetryProvider類圖以及相關操作示例圖如下:
RetryProvider主要用於對方法的重新執行操作,在後台線程BackgroundWorker對執行方法進行相應的控制和處理,主要提供以下2種方法:
(1)public void StartAsync(Action target, int waitTimeout = 0, int retryCount = 1)
(2)public void StartAsyncFunc(Func<bool> target, int waitTimeout = 0, int retryCount = 1)
第一種方法主要針對於無返回參數的方法,第二種方法主要針對於返回bool參數的方法,當然你也可以擴展該類,支持相關的其他參數的方法。方法具體如下所示:
StartAsync(Action target, waitTimeout = , retryCount = StartAsyncFunc(Func<> target, waitTimeout = , retryCount = StartAsyncRetry( target, waitTimeout, (target == ArgumentNullException( (._backgroupThread == ._backgroupThread = ._backgroupThread.WorkerSupportsCancellation = ._backgroupThread.WorkerReportsProgress = ._backgroupThread.DoWork +=._backgroupThread.ProgressChanged += (.WaitTimeout =.RetryCount =
在後台線程中執行的方法,主要根據RetryCount和BackgroundWorker的CancellationPending屬性進行相應的控制和處理,同時根據方法重試次數來報告相關進度,代碼如下:
Start( (target == retryCount = ._backgroupThread.ReportProgress( (! (.PerRetryBegin != .PerRetryBegin(.RetryCount - (target.GetType() == ((target Func<> InvalidOperationException( (.PerRetryFailedCompleted != ._backgroupThread.ReportProgress((.RetryCount - retryCount + ) * / (.PerRetryEnd != .PerRetryEnd(.RetryCount - (.RetryCount > -- (retryCount == ( (.Cancelled !=
目前只提供Action和Func<bool>參數的重試方法,因此只需要檢測下參數類型(如target.GetType() == typeof(Action))就可以進行相應的操作。如果傳入的參數是Func<bool>類型的,目前的處理方式為:檢測方法是否執行成功,如果返回true,即if ((target as Func<bool>).Invoke()),則退出重試操作後台線程,不在執行相應重試操作,否則拋出異常繼續執行操作。
Thread.Sleep(this.WaitTimeout)主要為阻塞當前線程,等待設置的Timeout時間,然後繼續執行相關方法。
(1)啟動重試方法,設置相應參數以及相關事件。
btnStart_Click( waitTimeout = .TryParse(.nupWaitTimeout.Value.ToString(), retryCount = .TryParse(.nupRetryCount.Value.ToString(), Start( waitTimeout, (._retryProvider == ._retryProvider = ._retryProvider.PerRetryFailedCompleted +=._retryProvider.Cancelled +=._retryProvider.PerRetryBegin +=._retryProvider.PerRetryEnd +=._retryProvider.ProgressChanged +=._retryProvider.Completed += (.btnStart.Enabled = (.listBoxRecord.Items.Count > ._retryProvider.StartAsyncFunc(ThrowExceptionMethod, waitTimeout *
相應的事件如下:
public delegate void CompletedEventHandler(bool success); //RetryProvider完成委托
public event CompletedEventHandler Completed; //RetryProvider完成事件
public delegate void CancelledEventHandler(); //RetryProvider取消委托
public event CancelledEventHandler Cancelled; //RetryProvider取消事件
public delegate void PerRetryBeginEventHandler(int retryIndex); //RetryProvider每一次重試開始操作委托,參數retryIndex重試次數,從0開始
public event PerRetryBeginEventHandler PerRetryBegin; //RetryProvider每一次重試開始操作事件
public delegate void PerRetryEndEventHandler(int retryIndex); //RetryProvider每一次重試結束操作委托,參數retryIndex重試次數,從0開始
public event PerRetryEndEventHandler PerRetryEnd; //RetryProvider每一次重試結束操作事件
public delegate void PerRetryFailedEventHandler(Exception ex); //RetryProvider每一次重試失敗委托,參數Exception為失敗的異常信息
public event PerRetryFailedEventHandler PerRetryFailedCompleted; //RetryProvider每一次重試失敗事件
public delegate void ProgressChangedEventHandler(int percent); //RetryProvider進度更改委托
public event ProgressChangedEventHandler ProgressChanged; //RetryProvider進度更改事件
(2)取消重試操作:
btnCancel_Click( (._retryProvider !=
該方法將導致後台線程執行CancelAsync操作,在重試操作中,如果檢測到後台線程的CancellationPending為true,則會觸發Cancelled事件,退出後台線程。
RetryProvider的主要是針對重試操作的封裝。考慮重試操作的操作時間可能較長,因此采用BackgroundWorker來進行相應的處理和控制。這種主要用於執行操作可控制的情況,對於不可控的,比如調用第三方程序進行相應操作(如調用MATLAB進行命令操作),等待時間和執行時間不確定,最佳方法為用Timer定時觸發進度條循環滾動,後台線程執行相應操作,線程執行完以後再設置相應內容。
:重試解決方案文件