I have a Service Class that Starts and Stops a task that is intended to run in the background behind a forms app.
When stopping the monitor:
Once the Stop()
method is called, no breakpoints are hit on the Monitor Task and IsStarted
never becomes false' and is stuck in an infinite loop.
What is wrong with this? Why does the Monitor Task seeming stop running? How do I fix this?
private volatile bool IsStarted = false;
public void Start(PartList partList, UnioServiceSettings settings, Action<string, string, string> createSummaryFile)
{
_Settings = settings;
_PartList = partList;
_cts = new CancellationTokenSource();
Task.Run(async() => await Monitor(_cts.Token)); //no difference:.ConfigureAwait(false);
_ProgressMessage?.Report("Monitor Started...");
IsStarted = true;
}
public async Task<bool> Stop()
{
if (IsStarted)
{
_ProgressMessage?.Report("Stopping Monitor...");
_cts.Cancel();
while (IsStarted) //this loop runs forever
{
await Task.Delay(1000); //.ConfigureAwait(false);? no difference
}
return true;
}
else
{
_ProgressMessage?.Report("Cannot stop Monitor. It has not been started.");
return false;
}
}
private async Task Monitor(CancellationToken token)
{
while (!token.IsCancellationRequested)
{
//do stuff
await Task.Delay(_Settings.DelayMs,token).ConfigureAwait(false);
}
IsStarted = false;
return;
}
CodePudding user response:
There is a race condition here:
Task.Run(async() => await Monitor(_cts.Token));
_ProgressMessage?.Report("Monitor Started...");
IsStarted = true;
It is possible that the Task
created by the Task.Run
method will complete on another thread before the current thread calls IsStarted = true;
. So eventually the IsStarted
will settle at the value true
without a Task
running. To solve this problem you could transfer the responsibility of mutating the IsStarted
field exclusively to the Monitor
method itself:
private async Task Monitor(CancellationToken token)
{
IsStarted = true;
try
{
_ProgressMessage?.Report("Monitor Started...");
while (true)
{
token.ThrowIfCancellationRequested();
//do stuff
await Task.Delay(_Settings.DelayMs,token).ConfigureAwait(false);
}
}
finally
{
IsStarted = false;
}
}
I don't know if this race condition is the cause of your problem though.