使用单个取消令牌添加中止所有任务

时间:2017-03-21 07:05:36

标签: c# .net multithreading threadpool cancellationtokensource

我收到的服务可以同时执行许多任务。我被分配了一个中止选项,它应该结束所有当前正在运行的任务。因为系统已经实现,所以将CancellationTokenSource传递给每个任务都是有问题的,所以我所做的就是创建一个所有任务都会听取取消的单一任务。当abort recive时,该令牌将发送取消,然后将创建一个新的CancellationTokenSource实例。 我无法验证所有任务,直到中止结束之前启动了一个新的CancellationTokenSource实例。

几个Q:

  1. 起初我认为TokenSource.Cancel()只是一个发送的事件,但它似乎被卡在"高,#34;所以任何具有相同令牌的新任务也会被取消,这是真的吗?

  2. 理想情况下,每个任务都有自己的取消令牌(对吗?),那个人需要持有该令牌?谁调用了任务或任务本身?因为一旦发送取消,我将永远保留该令牌,因为我无法告知任务何时到达出口点。

  3. 是否有一种已经实施的方法来监控所有当前正在运行的任务,因此当发送取消时,我会确保在允许任何新任务之前所有任务都已结束?我是用信号量做的,但它看起来像是一种可怕的闷热......

  4. 很抱歉新手问题,我已经实现了我需要的东西并且它有效,但质量低于标准,我希望以正确的方式改进它。

1 个答案:

答案 0 :(得分:4)

  1. 任务未接收任何取消。它只是令牌的状态变化。任务必须观看令牌,如果有取消请求,则任务可能会取消操作。

  2. 每个任务都有自己的令牌,因为CancellationTokenstruct并且会按值复制。要查看令牌(请参阅1.),任务必须保留令牌。

  3. 不,您必须等待任务,并且您无法强制取消任务。使用取消操作,您只发送取消请求,正在运行的任务可能取消或成功完成(取决于实施)。尚未启动的任务(等待运行)将被调度程序取消(它们根本不会启动)

  4. 作为一个例子,如何实现这样的取消,你在这里寻找一个非常简单的样本

    原始服务

    public interface IFooService
    {
        Task DoAsync( CancellationToken cancellationToken );
    }
    

    和将处理取消的那个

    public interface ICancelableFooService : IFooService
    {
        Task CancelAsync();
    }
    
    public class CancelableFooService : ICancelableFooService
    {
        private readonly IFooService _foo_service;
        private readonly object _sync = new object();
        private List<Task> _createdtasks = new List<Task>();
        private CancellationTokenSource _cts = new CancellationTokenSource();
    
        public CancelableFooService(IFooService foo_service)
        {
            _foo_service = foo_service;
        }
    
        public async Task CancelAsync()
        {
            _cts.Cancel();
            var t = Task.WhenAll( _createdtasks );
            try
            {
                await t;
            }
            catch { /* we eat all exceptions here */ }
            lock( _sync )
            {
                _cts = new CancellationTokenSource();
                _createdtasks.Clear();
            }
        }
    
        public Task DoAsync( CancellationToken cancellationToken )
        {
            lock(_sync)
            {
                var cts = CancellationTokenSource.CreateLinkedTokenSource( _cts.Token, cancellationToken );
                var token = cts.Token;
                var task = _foo_service.DoAsync( token );
                _createdtasks.Add( task );
            }
            return task;
        }
    }