Как реализовать отменяемый рабочий поток
Я пытаюсь реализовать отменяемый рабочий поток, используя новые конструкции потоков в пространстве имен System.Threading.Tasks. До сих пор я придумал эту реализацию:
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.
}
}
}
когда Stop()
Я ожидаю возвращения Worker.Status
быть TaskStatus.Canceled
,
Мои юнит-тесты показали, что при определенных условиях Worker.Status
остается установленным TaskStatus.Running
,
Это правильный способ реализации отменяемого рабочего потока?
1 ответ
Я считаю, что проблема в вашем звонке
Worker.Wait(_cancellationTokenSource.Token);
Это ждет, пока токен не будет сигнализирован - это уже есть, потому что вы только что позвонили Cancel()
, Если вы измените это просто
Worker.Wait();
тогда я верю, что вы увидите состояние RanToCompletion
, Вы не увидите Отменено, потому что ваша задача не бросает OperationCanceledException
, Если вы измените свой RunTasks
метод для вызова
cancellationToken.ThrowIfCancellationRequested()
в конце, то вам нужно поймать AggregateException
в Stop
- но тогда вы увидите состояние Canceled
в конце.
По крайней мере, так показывают мои эксперименты:)