2013-11-25 125 views
2

我有一个示例代码,取自MSDN,我希望在while循环中实现暂停/恢复功能。任何人都可以提出一个解决方案/ parern哪个会牵扯到这个?异步任务暂停循环恢复

private async void startButton_Click(object sender, RoutedEventArgs e) 
    { 
     resultsTextBox.Clear(); 

     // Instantiate the CancellationTokenSource. 
     cts = new CancellationTokenSource(); 

     try 
     { 
      await AccessTheWebAsync(cts.Token); 
      resultsTextBox.Text += "\r\nDownloads complete."; 
     } 
     catch (OperationCanceledException) 
     { 
      resultsTextBox.Text += "\r\nDownloads canceled.\r\n"; 
     } 
     catch (Exception) 
     { 
      resultsTextBox.Text += "\r\nDownloads failed.\r\n"; 
     } 

     cts = null; 
    } 


    private void cancelButton_Click(object sender, RoutedEventArgs e) 
    { 
     if (cts != null) 
     { 
      cts.Cancel(); 
     } 
    } 


    async Task AccessTheWebAsync(CancellationToken ct) 
    { 
     HttpClient client = new HttpClient(); 

     // Make a list of web addresses. 
     List<string> urlList = SetUpURLList(); 

     // ***Create a query that, when executed, returns a collection of tasks. 
     IEnumerable<Task<int>> downloadTasksQuery = 
      from url in urlList select ProcessURL(url, client, ct); 

     // ***Use ToList to execute the query and start the tasks. 
     List<Task<int>> downloadTasks = downloadTasksQuery.ToList(); 

     // ***Add a loop to process the tasks one at a time until none remain. 
     while (downloadTasks.Count > 0) 
     { 
       // Identify the first task that completes. 
       Task<int> firstFinishedTask = await Task.WhenAny(downloadTasks); 

       // ***Remove the selected task from the list so that you don't 
       // process it more than once. 
       downloadTasks.Remove(firstFinishedTask); 

       // Await the completed task. 
       int length = await firstFinishedTask; 
       resultsTextBox.Text += String.Format("\r\nLength of the download: {0}", length); 
     } 
    } 
+0

可能重复:http://stackoverflow.com/q/19613444/1768303 – Noseratio

回答

4

有一个MSDN article,这使用PauseToken(类似于CancellationToken)解决了。

下面是这篇文章的示例代码演示了这一概念:

namespace PauseTokenTestApp 
{ 
    public class PauseTokenSource 
    { 
     private volatile TaskCompletionSource<bool> m_paused; 
     internal static readonly Task s_completedTask = Task.FromResult(true); 

     public bool IsPaused 
     { 
      get { return m_paused != null; } 
      set 
      { 
       if (value) 
       { 
        Interlocked.CompareExchange(
         ref m_paused, new TaskCompletionSource<bool>(), null); 
       } 
       else 
       { 
        while (true) 
        { 
         var tcs = m_paused; 
         if (tcs == null) return; 
         if (Interlocked.CompareExchange(ref m_paused, null, tcs) == tcs) 
         { 
          tcs.SetResult(true); 
          break; 
         } 
        } 
       } 
      } 
     } 
     public PauseToken Token { get { return new PauseToken(this); } } 

     internal Task WaitWhilePausedAsync() 
     { 
      var cur = m_paused; 
      return cur != null ? cur.Task : s_completedTask; 
     } 
    } 

    public struct PauseToken 
    { 
     private readonly PauseTokenSource m_source; 
     internal PauseToken(PauseTokenSource source) { m_source = source; } 

     public bool IsPaused { get { return m_source != null && m_source.IsPaused; } } 

     public Task WaitWhilePausedAsync() 
     { 
      return IsPaused ? 
       m_source.WaitWhilePausedAsync() : 
       PauseTokenSource.s_completedTask; 
     } 
    } 

    class Program 
    { 
     static void Main() 
     { 
      var pts = new PauseTokenSource(); 
      Task.Run(() => 
      { 
       while (true) 
       { 
        Console.ReadLine(); 
        pts.IsPaused = !pts.IsPaused; 
       } 
      }); 
      SomeMethodAsync(pts.Token).Wait(); 
     } 

     public static async Task SomeMethodAsync(PauseToken pause) 
     { 
      for (int i = 0; i < 100; i++) 
      { 
       Console.WriteLine(i); 
       await Task.Delay(100); 
       await pause.WaitWhilePausedAsync(); 
      } 
     } 
    } 
}