代码之家  ›  专栏  ›  技术社区  ›  Arnold Zokas

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

  •  5
  • Arnold Zokas  · 技术社区  · 14 年前

    我正在尝试使用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 .
    我的单元测试表明在某些条件下 工人地位 剩余设置为 TaskStatus.Running .

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

    1 回复  |  直到 14 年前
        1
  •  5
  •   Jon Skeet    14 年前

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

    Worker.Wait(_cancellationTokenSource.Token);
    

    那是在等 令牌 已经发出信号了,因为你刚刚打过电话 Cancel() . 如果你把它改成

    Worker.Wait();
    

    那么我相信你会看到 RanToCompletion . 您不会看到取消,因为您的任务没有引发 OperationCanceledException . 如果你改变你的 RunTasks 调用方法

    cancellationToken.ThrowIfCancellationRequested()
    

    最后,你需要抓住 AggregateException 在里面 Stop -但是你会看到一种状态 Canceled 最后。

    至少,我的实验证明了这一点:)