Below is a simple C# Windows Forms program for .NET Framework 4.6.2.
The program objective is to start an infinite loop by clicking a Start button 1 and then end the loop gracefully by clicking a Stop button 2. If this first loop is not running, I also want the option to start a second infinite loop by clicking Start button 3 and stopping the second loop using Stop button 2.
Here's the Windows form:
I have implemented async void to do this. I couldn't find a more elegant way and it seems to work ok. Here's the code:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace CancelLoopTest
{
    public partial class Form1 : Form
    {
        private static CancellationTokenSource myCTS;
        private static CancellationToken myToken;
        public Form1()
        {
            InitializeComponent();
        }
        private async void button1_Click(object sender, EventArgs e)
        {
            try
            {
                button1.Enabled = false;
                myCTS = new CancellationTokenSource();
                myToken = myCTS.Token;
                while (!myToken.IsCancellationRequested)
                {
                    Console.WriteLine("Loop A running");
                    // Do stuff here that takes about 4.0 seconds
                    await Task.Delay(20);
                }
                Console.WriteLine("Loop A has stopped");
            }
            finally
            {
                button1.Enabled = true;
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            Console.WriteLine("Stop button clicked");
            myCTS?.Cancel();
        }
        private async void button3_Click(object sender, EventArgs e)
        {
            try
            {
                button3.Enabled = false;
                myCTS = new CancellationTokenSource();
                myToken = myCTS.Token;
                while (!myToken.IsCancellationRequested)
                {
                    Console.WriteLine("Loop B running");
                    // Do stuff here that takes about 0.3s
                    await Task.Delay(20);
                }
                Debug.WriteLine("Loop B has stopped");
            }
            finally
            {
                button3.Enabled = true;
            }
        }
    }
}
My main question: I have used a 20ms delay. In practice, I don't want any delay to hold up the loop. All I want is for the loop to sense whether the Stop button has been pressed. What millisecond value should I put in await Task.Delay(value) to ensure that clicking the Stop button will be detected? Or am I misunderstanding the purpose of await Task.Delay(value)?
Secondary question: This program allows Loop A and Loop B to run concurrently. Both loops are cancelled when Stop is clicked. In practice, I would like to allow only either Loop A or Loop B to run in isolation. Is there an elegant way to prevent Loop B from running if Loop A is already running (and vice-versa)?
Thank you.

 
     
     
    