2016-10-11 37 views
2

我意識到這不是取消任務的第一個線程,但我沒有找到適合我需求的任何合適的東西。C#UWP取消任務+信令子

這裏的情況:

  • 我有一個模塊化的系統,其中模塊由控制器類進行初始化,動態根據配置。
  • 每個模塊實現Connect()方法。該方法本身是黑匣子,但對於背景信息:某些模塊嘗試創建藍牙連接。
  • 如果連接時間過長,我想取消嘗試並在5分鐘內重試。

起初,我把重試邏輯放在模塊實現中。這很好,但在模塊上重複使用,並不屬於模塊的核心職責。於是我考慮把邏輯放在控制器中,但我努力尋找一個很好的實現。

這裏的問題是我不僅想要取消任務,我想以一種很好的方式來完成任務。如果有物體需要關閉/處置,模塊應該可以這樣做。此外,該模塊應該能夠將其狀態設置爲「斷開連接」而不是「連接」(並且我寧願讓模塊執行該操作,也不要使用公共方法,以便外部更改狀態)。當連接和超時邏輯位於模塊內部時,這很容易,但引入外部超時變得更具挑戰性。

這裏是我可以預見,當一個模塊沒有及時響應的流程:

  • 控制器創建一個新的模塊實例
  • 控制器,以連接模塊
  • 控制器還初始化調用connect()一個定時器監視模塊在30秒內完成連接
  • 計時器關閉,模塊尚未完成工作尚未
  • Connect()方法應該被通知取消最好通過在可以捕獲和處理的Connect方法內拋出異常。
  • 異常處理程序可以清理乾淨的東西,方法返回。

上面的流程並不存在,據我所知。取消令牌的工作方式不同,並要求我進行事件或輪詢。這很好,但是我回過頭來將這個邏輯包含到我的模塊中,爲什麼不直接在那裏做整個重試。所以我想知道是否有任何甜美的圖案可以讓我這樣做。

我正在爲Windows 10 UWP構建。我沒有特意加入任何代碼,因爲我現在擁有的東西無論如何都是垃圾。

回答

1

不要讓CancellationToken出現什麼問題,您的異步操作支持取消,或者沒有辦法停止正在執行的代碼,除非您終止線程或進程。 這是一個超時示例。

public static async Task Run() 
      { 
       var module = new Module(); 

       //No timeout 
       await module.Connect(1, CancelAfter(2000)); 

       try 
       { 
        // Timeout 
        await module.Connect(5, CancelAfter(1000)); 
       } 
       catch (Exception) 
       { 

        module.Dispose(); 
       } 

      } 

      public static CancellationToken CancelAfter(int millisecondsDelay) 
      { 
       var token = new CancellationTokenSource(); 
       token.CancelAfter(millisecondsDelay); 
       return token.Token; 
      } 

      public class Module : IDisposable 
      { 
       public async Task Connect(int count, CancellationToken cancel) 
       { 
        for (int i = 0; i < count; i++) 
        { 
         //This is just to simulte some work Task.Delay can be canceled as well with Task.Delay(500,cancel) 
         await Task.Delay(500); 
         cancel.ThrowIfCancellationRequested(); 
        } 
       } 

       public void Dispose() 
       { 

       } 
      } 

可以超時任何任務與

public static class TaskTimeout 
    { 
     public static async Task TimeoutAfter(this Task task, int millisecondsTimeout) 
     { 
      if (task != await Task.WhenAny(task, Task.Delay(millisecondsTimeout))) 
      { throw new TimeoutException(); } 
     } 

     public static async Task<T> TimeoutAfter<T>(this Task<T> task, int millisecondsTimeout) 
     { 
      if (task != await Task.WhenAny(task, Task.Delay(millisecondsTimeout))) 
      { throw new TimeoutException(); } 
      else { return task.Result; } 
     } 
    } 

但這不會取消你的連接只有當連接是取消它可以取消。大多數.net中的Async調用都實現了CancellationToken,因此如果您的連接使用了它。

+0

這正是問題所在。 My Connect()沒有for或while循環,我可以一次又一次地檢查令牌。它會觸發連接呼叫,並且會一直等到有連接。這是我需要以某種方式殺死的那個呼叫,目前我通過從計時器事件中處置對象來完成。如果我們可以在任何給定的時間點觸發Connect()方法中的運行時異常,那將會更好。 – Jasper

+0

我做了一個編輯,告訴你如何超時任何任務,但你的配置需要處理處置。 –