【问题标题】:Several tasks cancellation几个任务取消
【发布时间】:2014-05-01 20:20:32
【问题描述】:

有一个顶级任务会启动另一个任务。

var token = _cancellationTokenSource.Token;
_task = new Task(() => WorkAction(this, token), token); //Top level task

内部任务实现是:

public string FindDevice(IProgressViewModel progressViewModel, 
                         CancellationToken cancellationToken) {

        for (int i = 0; i < orderedComPortsList.Count; i++) {
            try {
                cancellationToken.ThrowIfCancellationRequested();
            } catch (OperationCanceledException) {
                return null;
            }
            string curPort = orderedComPortsList[i];
            if (InnerIsDeviceOnline(deviceModelId, curPort)) //The real long work
                return curPort;
            progressViewModel.CurrentValue = i;
        }
        return null;
    }

使用此实现,仅当最后一个 InnerIsDeviceOnline 结束时才会发生取消。如何实现 FindDevice 使其立即可取消?

更新 1。

我们可以这样做吗:

 bool? result = null;
            Task<bool> parent = new Task<bool>(() => {
                bool? res = result;
                Task.Factory.StartNew(() => {
                    while (res==null) {                           
                        cancellationToken.ThrowIfCancellationRequested();
                        Thread.Sleep(50);
                    }
                }, TaskCreationOptions.AttachedToParent);

                result = InnerIsDeviceOnline(deviceModelId, comPort);
                return result.Value;
            }, cancellationToken);

            return parent;

它的问题是它永远不会完成(我不知道为什么)。但这让我们立即取消。

【问题讨论】:

  • 所以WorkAction 是另一个使用相同CancellationToken 的任务?
  • 如果您需要在期间 InnerIsDeviceOnline 完成任务,那么您需要为该方法添加取消支持。
  • 你明白这样只会让洞更深吗?迟早会有需要很长时间的调用,而那个调用是我无法控制的。
  • 您是否明白,如果您使孔更深,您将无法获得所需的控制?真正的取消支持意味着能够在任何时候(优雅地)停止,如果 InnerIsDeviceOnline 超出您的控制范围,那么取消也是如此。
  • 嗯,好的,我稍后会更新帖子。

标签: c# .net c#-4.0 task multitasking


【解决方案1】:

为了优雅地取消长时间运行的操作,您的整个 API 需要以您需要的特定粒度支持取消。如果长时间运行操作的 API 不支持 CancellationToken,您需要提供接口层来提供该支持。比如异步的WebRequest.BeginGetResponse不支持CancellationToken,但是我可以通过这个扩展方法支持它,它调用Abort()来响应CancellationToken被取消:

https://github.com/openstacknetsdk/openstack.net/blob/master/src/corelib/Core/WebRequestExtensions.cs

【讨论】:

  • 我看了你的例子。好的,我会改写我的问题。如果我更改 FindDevice 的签名并从它返回 Task,是否有可能完成我所描述的?
  • 如果InnerIsDeviceOnline 等待取消的时间比您希望的要长,那么您需要为该方法的实现添加取消支持。否则,您的 API 整体将无法满足我提到的粒度要求。
  • 问题在于 InnerIsDeviceOnline 由单个非托管函数调用组成。我能用它做什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多