使用.NET 5 CancellationToken 调用可以在主线程上超时的方法

如何解决使用.NET 5 CancellationToken 调用可以在主线程上超时的方法

在 .NET Fx 4 中,我们曾经使用 this approach described here 来超时方法调用。这种方法依赖于在 .NET 5 中不起作用的 Thread.Abort(),如here “可能令人惊讶的是,Thread.Abort 从未在 .NET Core 中实现过”.

在这方法中非常有用的是被调用方法(可能超时的方法)在主线程上执行,该线程用于执行发起调用调用方法。在此调用之前,会触发一个 异步线程 以在超时间隔期间等待,然后最终在捕获 Thread.Abort()主线程调用 ThreadAbortException 并然后在 catch 处理程序中调用 Thread.ResetAbort()

我们如何才能对某些 .NET Core / .NET 5 代码具有相同的行为?

此 Microsoft 文档 Cancel async tasks after a period of time 显示了一些不同之处,其中可以在异步线程而不是在主线程调用可以超时的方法

解决方法

CancellationToken合作取消;如果您可以更改违规代码以定期检查令牌以查看它是否应该放弃,那么:就这样做。但是,您不能只在代码中添加 CancellationToken 并期望它开始执行(在触发时)类似于 Thread.Abort();这是非常不同的,因为它主动中断执行不需要被中断代码的任何合作。

,

有两点:

在 .NET Core/.NET5 中不再可能通过 .NET Fx 中的 Thread.Abort() / ThreadAbortException 实现的第一次抢先取消。正如@Marc Gravel 解释的那样,必须改用合作取消(其中可取消方法定期检查它是否已被取消)。因此,要取消的代码位于不接受 CancellationToken 的黑盒子中的情况无法在 .NET Core 中实现。

其次,可以在主线程上运行可取消方法,甚至不涉及池线程。以下是适用于 .NET Fx 和 .NET Core/.NET5 平台的 .NET Standard 代码示例:

using System;
using System.Threading;
using System.Threading.Tasks;
namespace ClassLibraryNetStandard {
   static class CancellationTokenTest_OpOnMainThread {
      internal static void Go() {
         bool b = WaitFor<int>.TryCallWithTimeout(
            500.ToMilliseconds(),// timeout
            OneSecondMethod,out int result);
         Console.WriteLine($"OneSecondMethod() {(b ? "Executed" : "Cancelled")}");
      }
      static int OneSecondMethod(CancellationToken ct) {
         for (var i = 0; i < 10; i++) {
            Thread.Sleep(100.ToMilliseconds());
            // co-operative cancellation: periodically check if CancellationRequested
            if (ct.IsCancellationRequested) {
               throw new TaskCanceledException();
            }
         }
         return 123; // the result
      }
      static TimeSpan ToMilliseconds(this int nbMilliseconds) 
         => new TimeSpan(0,nbMilliseconds);
   }
   static class WaitFor<TResult> {
      internal static bool TryCallWithTimeout(
            TimeSpan timeout,Func<CancellationToken,TResult> proc,out TResult result) {
         var cts = new CancellationTokenSource(timeout);
         try {
            result = proc(cts.Token);
            return true;
         } catch (TaskCanceledException) { }
         finally { cts.Dispose(); }
         result = default;
         return false;
      }
   }
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?