【问题标题】:How to wrap a single sync operation with a Task with a CancellationToken?如何使用具有 CancellationToken 的任务包装单个同步操作?
【发布时间】:2016-10-07 13:49:33
【问题描述】:

我有一个可能需要很长时间才能完成的同步操作。操作的调用者提供了一个CancellationToken,并且当令牌被取消时应该立即停止操作(在这种情况下取​​消后的几毫秒内也可以)。

如何使用 CancellationToken 将其包装在任务中?

我无法更改调用代码或调用本身。

曾经是什么:LongOperation();

我现在拥有的:await Task.Run(() => LongOperation(), cancellationToken).ConfigureAwait(false);

显然这不起作用,因为您必须在给予Task.Run 的操作中轮询令牌。

【问题讨论】:

  • 如您所见,您必须在您说无法修改的代码中执行此操作。在代码没有意识到的情况下随意中止执行很容易导致某些资源处于无效/损坏状态。见this related question
  • 你做不到。您的同步方法需要接受 CancallationToken 并且您需要定期检查是否应该中断令牌信号的执行。如果您无法更改同步方法 async/await 将无济于事。您可以创建一个新线程执行线程并按需使用 Abort。 stackoverflow.com/questions/2251964/…

标签: c# .net async-await


【解决方案1】:

我无法更改调用代码或调用本身。

显然这不起作用,因为您必须轮询赋予 Task.Run 的操作中的令牌。

最简单的解决方案是取消其中一项要求:要么允许CancellationToken 被忽略,要么更改被调用的代码。

如果这真的、真的、真的不可能,那么您需要在另一个进程中运行代码。因此,您需要启动一个可以访问该方法的子进程,将所有参数编组给它,然后编组返回任何结果值或异常。然后,当令牌被取消时,终止进程。

执行相同操作的方法不太安全:您可以在另一个AppDomain 中运行代码并在取消时关闭AppDomain,或者您可以在另一个ThreadAbort 中运行代码@ 987654327@ 取消。但这两者都容易导致资源泄漏或应用程序稳定性问题。唯一真正安全的方法是单独的进程。

【讨论】:

  • 对于 OP,也不要被启动和发送参数给单独的进程吓倒。我不得不做类似的事情,WCF over named pipes 让这个过程相对轻松。
  • @ScottChamberlain:好点子!上次我必须这样做 WCF 还不存在(.NET 也不存在),所以它是直接的 stdin/stdout/stderr 重定向 - 使用多个线程来防止死锁。丑!
  • 在长时间运行的同步方法调用期间终止进程也可能不是最好的主意。我闻到内存泄漏的味道。
  • @Botonomous:这是不可能的——从操作系统的角度来看,这个过程是资源使用的范围。如果你终止一个进程,它的所有内存都将被回收。
  • @StephenCleary 终止进程是否会确保所有资源(从新进程中开始)都被实际释放?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-09
  • 2015-03-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多