Home > Software design >  Pause and resume a looping Task without using TaskCompletionSource
Pause and resume a looping Task without using TaskCompletionSource

Time:07-13

I have a simple program that inputs a number and starts counting from 0, I have 1 counter to do pause and resume (_nCurrentCount), the below code works fine, but I canceled Task on pause right?. Is there a way to just "pause" that Task without canceling it?

 private void btnStart_Click(object sender, EventArgs e)
    {
        btnCancel.Enabled = true;
        

        //Pause
        if (tokenSource != null)
        {
            btnStart.Text = "RESUME";
            tokenSource.Cancel();
            tokenSource.Dispose();
            tokenSource = null;
        }
        //Start and resume
        else
        {
            tokenSource = new CancellationTokenSource();
            btnStart.Text = "PAUSE";

            countNumber(_nCurrentCount, tokenSource.Token).ContinueWith((t) =>
            {
                var _bPaused = false;

                if (!Disposing && !IsDisposed && tokenSource != null)
                    tokenSource.Token.ThrowIfCancellationRequested();

                if (InvokeRequired)
                {
                    Invoke((MethodInvoker)(() =>
                    {
                        txtCount.Text = _nCurrentCount.ToString();
                        btnStart.Enabled = false;
                    }));
                }

                if (t.IsFaulted)
                {
                }
                else if (t.IsCanceled)
                {
                    _bPaused = true;
                }
                else
                {
                    _bPaused = false;
                    _nCurrentCount = -1;
                    tokenSource.Dispose();
                    tokenSource = null;
                    btnStart.Text = "START";
                }

            }, TaskContinuationOptions.ExecuteSynchronously);
        }
    }

This is the countNumber Task:

private async Task countNumber(int pnStart, CancellationToken pCancellationToken)
    {
        if (pnStart < 0)
            pnStart = 0;
        for (int i = pnStart; i <= Convert.ToInt32(txtInput.Text); i  )
        {
            pCancellationToken.ThrowIfCancellationRequested();

            pnStart = i;
            _nCurrentCount = i;
            txtCount.Text = _nCurrentCount.ToString();
            
            await Task.Delay(500);
        }
    }

CodePudding user response:

Here's a version using async:

private int _target = 0;
private int _counter = 0;
private CancellationTokenSource cts = null;

private async Task Execute(CancellationToken ct)
{
    while (true)
    {
        txtCount.Text = $"{  _counter}";
        if (_counter == _target)
        {
            btnStart.Text = "START";
            break;
        }
        await Task.Delay(TimeSpan.FromMilliseconds(500.0));
        if (ct.IsCancellationRequested)
        {
            break;
        }
    }
}

private async void btnStart_Click(object sender, EventArgs e)
{
    if (_target == _counter)
    {
        if (int.TryParse(txtInput.Text, out int target) && target > 0)
        {
            _target = target;
            _counter = 0;
            txtCount.Text = $"{_counter}";
            btnStart.Text = "PAUSE";
            cts = new CancellationTokenSource();
            await Execute(cts.Token);
        }
        else
        {
            txtCount.Text = "INVALID";
        }
    }
    else
    {
        if (cts != null)
        {
            cts.Cancel();
            cts = null;
            btnStart.Text = "RESUME";
        }
        else
        {
            btnStart.Text = "PAUSE";
            cts = new CancellationTokenSource();
            await Execute(cts.Token);
        }
    }
}

private int _target = 0;
private int _counter = 0;

private async Task Execute()
{
    while (true)
    {
        if (btnStart.Text == "PAUSE")
        {
            txtCount.Text = $"{  _counter}";
            if (_counter == _target)
            {
                btnStart.Text = "START";
                break;
            }
        }
        await Task.Delay(TimeSpan.FromMilliseconds(500.0));
    }
}

private async void btnStart_Click(object sender, EventArgs e)
{
    if (btnStart.Text == "START")
    {
        if (int.TryParse(txtInput.Text, out int target) && target > 0)
        {
            _target = target;
            _counter = 0;
            txtCount.Text = $"{_counter}";
            btnStart.Text = "PAUSE";
            await Execute();
        }
        else
        {
            txtCount.Text = "INVALID";
        }
    }
    else
    {
        btnStart.Text = btnStart.Text == "RESUME" ? "PAUSE" : "RESUME";
    }
}
  • Related