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.