2

I have a sample code, taken from MSDN, to which I would like implement the Pause / Resume functionality within while loop. Could anybody propose a solution / parern which would hande this?

 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);
        }
    }
1

1 Answer 1

6

There is an MSDN article that solves this using a PauseToken (similar to a CancellationToken).

Here's the sample code from that article that demonstrates this concept:

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();
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.