I'm trying to implement a cancellable worker thread using the new threading constructs in System.Threading.Tasks namespace. So far I have have come up with this implementation:
public sealed class Scheduler
{
private CancellationTokenSource _cancellationTokenSource;
public System.Threading.Tasks.Task Worker { get; private set; }
public void Start()
{
_cancellationTokenSource = new CancellationTokenSource();
Worker = System.Threading.Tasks.Task.Factory.StartNew(
() => RunTasks(_cancellationTokenSource.Token),
_cancellationTokenSource.Token
);
}
private static void RunTasks(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
Thread.Sleep(1000); // simulate work
}
}
public void Stop()
{
try
{
_cancellationTokenSource.Cancel();
Worker.Wait(_cancellationTokenSource.Token);
}
catch (OperationCanceledException)
{
// OperationCanceledException is expected when a Task is cancelled.
}
}
}
When Stop()
returns I expect Worker.Status
to be TaskStatus.Canceled
.
My unit tests have shown that under certain conditions Worker.Status
remains set to TaskStatus.Running
.
Is this a correct way to implement a cancellable worker thread?
I believe that the problem is in your call to
Worker.Wait(_cancellationTokenSource.Token);
That's waiting for the token to be signalled - which it already is, because you've just called Cancel()
. If you change that to just
Worker.Wait();
then I believe you'll see a state of RanToCompletion
. You won't see Canceled, because your task isn't throwing OperationCanceledException
. If you change your RunTasks
method to call
cancellationToken.ThrowIfCancellationRequested()
at the end, then you'll need to catch an AggregateException
in Stop
- but then you'll see a state of Canceled
at the end.
At least, that's what my experimentation shows :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With