如何从TaskCompletionSource取消任务?

Nis*_*lon 3 c# asynchronous

我正在尝试创建一个异步ProducerConsumerCollection,为此,我正在使用此msdn页面(http://msdn.microsoft.com/zh-cn/library/hh873173.aspx(页面底部))。

我现在正在尝试添加超时,这是我的工作:

    public async Task<T> TakeWithTimeout(int timeout)
    {
            Task<T> takeTask = this.Take();

            if (timeout <= 0 || takeTask == await Task.WhenAny(this.tasks.Take(), Task.Delay(timeout)))
            {
                return await takeTask;
            }
            else
            {
                // Timeout
                return default(T);
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

此代码的问题在于,在超时的情况下,它不会取消Take()方法创建的任务。

由于此任务是由TaskCompletionSource“创建”的,因此我不能给它一个CancellationToken吗?

因此,如何继续取消它并正确实现此Take with timeout?

谢谢 :)

Ste*_*ary 5

编写取消安全async友好的生产者/消费者集合并非易事。您需要做的是更改Take以接受a CancellationToken作为参数,并且它应该注册一个处理程序,以便在取消处理程序时将其TaskCompletionSource取消。

我强烈建议您使用BufferBlock<T>,它具有内置的取消支持。

如果您不能使用TPL数据流(例如,您在PCL中工作,或者数据流不支持目标平台),则可以使用开源AsyncEx库(例如AsyncProducerConsumerQueueAsyncCollection)中的生产者/消费者集合。这些都基于AsyncLockAsyncConditionVariable,我在自己的博客中简要介绍了该设计(该设计未涉及取消详细信息)。支持采用这种设计的生产者/消费者集合中的取消的关键是要支持中的取消AsyncConditionVariable.WaitAsync;一旦您的条件变量类型支持取消,那么您的集合也将轻松支持它。