如何实现可取消的工作线程

Arn*_*kas 5 multithreading .net-4.0 backgroundworker

我正在尝试使用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.
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Stop()回报我希望Worker.StatusTaskStatus.Canceled.
我的单元测试表明,在某些条件下Worker.Status仍然存在TaskStatus.Running.

这是实现可取消工作线程的正确方法吗?

Jon*_*eet 5

我相信问题出在你的电话中

Worker.Wait(_cancellationTokenSource.Token);
Run Code Online (Sandbox Code Playgroud)

那是等待令牌发出信号 - 它已经是,因为你刚刚打电话Cancel().如果你改变它只是

Worker.Wait();
Run Code Online (Sandbox Code Playgroud)

然后我相信你会看到一个状态RanToCompletion.你不会看到已取消,因为你的任务没有投掷OperationCanceledException.如果您更改RunTasks要拨打的方法

cancellationToken.ThrowIfCancellationRequested()
Run Code Online (Sandbox Code Playgroud)

在年底,那么你就需要捕捉的AggregateExceptionStop-但你会看到的状态Canceled在最后.

至少,这就是我的实验所显示的:)