重要前提
安装AI Skills的关键前提是:必须科学上网,且开启TUN模式,这一点至关重要,直接决定安装能否顺利完成,在此郑重提醒三遍:科学上网,科学上网,科学上网。查看完整安装教程 →
thread-abort-migration by dotnet/skills
npx skills add https://github.com/dotnet/skills --skill thread-abort-migration此技能帮助代理将使用 Thread.Abort 的 .NET Framework 代码迁移到现代 .NET (6+) 所需的协作式取消模型。在现代 .NET 中,Thread.Abort 会抛出 PlatformNotSupportedException —— 无法强制终止托管线程。该技能首先识别使用模式,然后应用正确的替换策略。
Thread.Abort 的 .NET Framework 项目迁移到 .NET 6+ThreadAbortException catch 块Thread.ResetAbort 调用Thread.InterruptThread.Abort 的使用 或 的 ASP.NET 代码广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
Response.EndResponse.Redirect(url, true)PlatformNotSupportedException 或 SYSLIB0006 警告Thread.Join、Thread.Sleep 或 Thread.Start,没有任何中止、中断或 ThreadAbortException catch 块。 这些 API 在现代 .NET 中工作方式相同 —— 无需迁移。请在此停止并告知用户无需迁移。如果您建议现代化(例如 Task.Run、Parallel.ForEach),您必须明确说明这些是与 Thread.Abort 迁移无关的可选改进,并且现有代码在目标框架上按原样编译和运行是正确的。| 输入 | 必需 | 描述 |
|---|---|---|
| 源项目或解决方案 | 是 | 包含 Thread.Abort 用法的 .NET Framework 项目 |
| 目标框架 | 是 | 要面向的现代 .NET 版本(例如 net8.0) |
| Thread.Abort 使用位置 | 推荐 | 引用 Thread.Abort、ThreadAbortException、Thread.ResetAbort 或 Thread.Interrupt 的文件或类 |
提交策略: 在每个模式替换后进行提交,以便迁移可审查和可二分查找。将相关的调用点(例如所有可取消的工作循环)分组到一个提交中。
在代码库中搜索所有与线程终止相关的 API:
Thread.Abort 和 thread.Abort()(实例调用)ThreadAbortExceptionThread.ResetAbortThread.InterruptResponse.End()(在 ASP.NET Framework 内部调用 Thread.Abort)Response.Redirect(url, true)(true 参数会触发 Thread.Abort)SYSLIB0006 杂注抑制记录每个使用位置,并对中止背后的意图进行分类。
将每种用法归类为以下模式之一:
| 模式 | 描述 | 现代替换方案 |
|---|---|---|
| 可取消的工作循环 | 运行应在请求时停止的循环的线程 | 在循环中检查 CancellationToken |
| 超时强制执行 | 中止超过时间限制的线程 | CancellationTokenSource.CancelAfter 或带有延迟的 Task.WhenAny |
| 阻塞调用中断 | 阻塞在 Sleep、WaitOne 或 Join 上需要唤醒的线程 | 带有 CancellationToken.WaitHandle 的 WaitHandle.WaitAny,或异步替代方案 |
| ASP.NET 请求终止 | Response.End 或 Response.Redirect(url, true) | 从操作方法返回;对长时间运行的请求工作使用 HttpContext.RequestAborted |
| ThreadAbortException 作为控制流 | 检查 ThreadAbortException 以决定清理操作的 catch 块 | 改为捕获 OperationCanceledException,并进行显式清理 |
| Thread.ResetAbort 以继续执行 | 捕获中止并调用 ResetAbort 以保持线程存活 | 检查 CancellationToken.IsCancellationRequested 并决定是否继续 |
| 非协作式代码终止 | 终止运行无法修改以检查取消的代码的线程 | 将工作移至单独的进程并使用 Process.Kill |
关键点: 根本性的范式转变是从抢占式取消(运行时强制注入异常)转变为协作式取消(代码必须主动检查并响应取消请求)。必须评估每个调用点,以确定目标代码是否可以修改为协作式。
CancellationToken 参数。替换循环条件或在安全检查点添加 token.ThrowIfCancellationRequested()。调用方创建 CancellationTokenSource 并调用 Cancel() 而不是 Thread.Abort()。new CancellationTokenSource(TimeSpan.FromSeconds(n)) 或 cts.CancelAfter(timeout)。将令牌传递给工作。对于基于任务的代码,使用 Task.WhenAny(workTask, Task.Delay(timeout, cts.Token)),如果延迟获胜则取消源;取消也会释放延迟的内部计时器。Thread.Sleep(ms) 替换为 Task.Delay(ms, token) 或 token.WaitHandle.WaitOne(ms)。将 ManualResetEvent.WaitOne() 替换为 WaitHandle.WaitAny(new[] { event, token.WaitHandle })。Response.End() —— 只需从方法返回。将 Response.Redirect(url, true) 替换为 Response.Redirect(url)(不带 true endResponse 参数)或返回重定向结果。在 ASP.NET Core 中,使用 HttpContext.RequestAborted 作为长时间运行请求工作的取消令牌。catch (ThreadAbortException) 替换为 catch (OperationCanceledException)。将清理逻辑移至 finally 块或 CancellationToken.Register 回调中。不要捕获 OperationCanceledException 并吞掉它 —— 让它传播,除非您有特定的恢复操作。ResetAbort 来防止拆除线程。在每个单元后检查 token.IsCancellationRequested 并决定是否继续。为每个新的工作单元创建一个新的 CancellationTokenSource(可选择链接到父令牌),而不是尝试重置现有的令牌源。CancellationToken(例如第三方库、本机调用),请将工作移至子进程。主机进程通过 stdin/stdout 或 IPC 进行通信,并在超时时调用 Process.Kill。迁移所有模式后,移除或替换任何剩余的引用:
| 已移除的 API | 替换方案 |
|---|---|
Thread.Abort() | CancellationTokenSource.Cancel() |
ThreadAbortException catch 块 | OperationCanceledException catch 块 |
Thread.ResetAbort() | 检查 token.IsCancellationRequested 并决定是否继续 |
Thread.Interrupt() | 通过 CancellationToken 发出信号或设置 ManualResetEventSlim(同样已过时:.NET 9 中的 SYSLIB0046) |
Response.End() | 移除调用;从方法返回 |
Response.Redirect(url, true) | 不带 endResponse 的 Response.Redirect(url),或返回重定向结果 |
#pragma warning disable SYSLIB0006 | 替换 Thread.Abort 调用后移除 |
SYSLIB0006 警告且没有与 Thread.Abort 相关的编译错误。Thread.Abort、ThreadAbortException、Thread.ResetAbort 或 Thread.Interrupt 引用。Thread.Abort 进行清理或超时,请更新它们以使用 CancellationToken。Thread.Abort 的引用ThreadAbortException catch 块Thread.ResetAbort 调用SYSLIB0006 杂注抑制CancellationToken 参数CancellationTokenSource.CancelAfter 或等效方案token.WaitHandle 的 WaitHandle.WaitAny 或异步替代方案| 陷阱 | 解决方案 |
|---|---|
添加 CancellationToken 参数但在长时间运行的代码中从不检查它 | 在循环中的定期检查点和昂贵操作之间插入 token.ThrowIfCancellationRequested()。只有在代码协作时取消才有效。 |
| 未将令牌传递到完整的调用链 | 链中的每个异步或长时间运行的方法都必须接受并转发 CancellationToken。如果链中的一个方法忽略了它,取消将在该点停滞。 |
期望 CancellationToken 中断阻塞的同步调用,如 Thread.Sleep 或 socket.Receive | 这些调用不检查令牌。将 Thread.Sleep(ms) 替换为 token.WaitHandle.WaitOne(ms)。将同步 I/O 替换为接受 CancellationToken 的异步重载。 |
捕获 OperationCanceledException 并吞掉它 | 让 OperationCanceledException 传播给调用者。仅在您决定取消后要做什么(记录、清理、返回结果)的顶级编排点捕获它。 |
未释放 CancellationTokenSource | CancellationTokenSource 是 IDisposable。将其包装在 using 语句中或在 finally 块中释放它。泄漏它会导致计时器和回调泄漏。 |
| 假设取消是立即的 | 协作式取消仅在下一个检查点生效。如果工作项很大或代码在检查之间有很长的间隔,取消可能会延迟。根据可接受的延迟设计检查点频率。 |
使用 Thread.Interrupt 作为 Thread.Abort 的替代品 | Thread.Interrupt 在现代 .NET 中也不推荐使用。它仅对处于 WaitSleepJoin 状态的线程有效,并抛出 ThreadInterruptedException,这是一个不同的异常类型。替换为 CancellationToken 信号。 |
移除 ThreadAbortException catch 块而未迁移清理逻辑 | ThreadAbortException catch 块通常包含关键清理(释放锁、回滚事务)。在移除 catch 之前,将此逻辑移至 finally 块或 CancellationToken.Register 回调中。 |
Thread.Abort 抛出 PlatformNotSupportedExceptionCancellationToken 的协作式取消模型Thread.Abort 已过时Thread.Interrupt 已过时(在 .NET 9 中添加)Task.WaitAsync(CancellationToken) —— 基于任务的代码的可取消等待(.NET 6+)每周安装次数
48
仓库
GitHub 星标数
725
首次出现
2026年3月10日
安全审计
安装于
github-copilot46
opencode46
kimi-cli44
gemini-cli44
amp44
cline44
This skill helps an agent migrate .NET Framework code that uses Thread.Abort to the cooperative cancellation model required by modern .NET (6+). Thread.Abort throws PlatformNotSupportedException in modern .NET — there is no way to forcibly terminate a managed thread. The skill identifies the usage pattern first, then applies the correct replacement strategy.
Thread.AbortThreadAbortException catch blocks that use control flow or cleanup logicThread.ResetAbort calls that cancel pending abortsThread.Interrupt for waking blocked threadsResponse.End or Response.Redirect(url, true), which internally call Thread.AbortPlatformNotSupportedException or SYSLIB0006 warnings after a target framework changeThread.Join, Thread.Sleep, or Thread.Start without any abort, interrupt, or ThreadAbortException catch blocks. These APIs work identically in modern .NET — no migration is needed. Stop here and tell the user no migration is required. If you suggest modernization (e.g., Task.Run, Parallel.ForEach), you must explicitly state these are optional improvements unrelated to Thread.Abort migration, and the existing code will compile and run correctly as-is on the target framework.| Input | Required | Description |
|---|---|---|
| Source project or solution | Yes | The .NET Framework project containing Thread.Abort usage |
| Target framework | Yes | The modern .NET version to target (e.g., net8.0) |
| Thread.Abort usage locations | Recommended | Files or classes that reference Thread.Abort, ThreadAbortException, Thread.ResetAbort, or Thread.Interrupt |
Commit strategy: Commit after each pattern replacement so the migration is reviewable and bisectable. Group related call sites (e.g., all cancellable work loops) into one commit.
Search the codebase for all thread-termination-related APIs:
Thread.Abort and thread.Abort() (instance calls)ThreadAbortException in catch blocksThread.ResetAbortThread.InterruptResponse.End() (calls Thread.Abort internally in ASP.NET Framework)Response.Redirect(url, true) (the true parameter triggers Thread.Abort)SYSLIB0006 pragma suppressionsRecord each usage location and classify the intent behind the abort.
Categorize every usage into one of the following patterns:
| Pattern | Description | Modern replacement |
|---|---|---|
| Cancellable work loop | Thread running a loop that should stop on demand | CancellationToken checked in the loop |
| Timeout enforcement | Aborting a thread that exceeds a time limit | CancellationTokenSource.CancelAfter or Task.WhenAny with a delay |
| Blocking call interruption | Thread blocked on Sleep, WaitOne, or Join that needs to wake up |
Critical: The fundamental paradigm shift is from preemptive cancellation (the runtime forcibly injects an exception) to cooperative cancellation (the code must voluntarily check for and respond to cancellation requests). Every call site must be evaluated for whether the target code can be modified to cooperate.
CancellationToken parameter. Replace the loop condition or add token.ThrowIfCancellationRequested() at safe checkpoints. The caller creates a CancellationTokenSource and calls Cancel() instead of Thread.Abort().new CancellationTokenSource(TimeSpan.FromSeconds(n)) or cts.CancelAfter(timeout). Pass the token to the work. For task-based code, use Task.WhenAny(workTask, Task.Delay(timeout, cts.Token)) and cancel the source if the delay wins; cancelling also disposes the delay's internal timer.After migrating all patterns, remove or replace any remaining references:
| Removed API | Replacement |
|---|---|
Thread.Abort() | CancellationTokenSource.Cancel() |
ThreadAbortException catch blocks | OperationCanceledException catch blocks |
Thread.ResetAbort() | Check token.IsCancellationRequested and decide whether to continue |
Thread.Interrupt() | Signal via or set a (also obsolete: in .NET 9) |
SYSLIB0006 warnings and no Thread.Abort-related compile errors.Thread.Abort, ThreadAbortException, Thread.ResetAbort, or Thread.Interrupt.Thread.Abort for cleanup or timeout, update them to use CancellationToken.Thread.Abort remain in the migrated codeThreadAbortException catch blocks remainThread.ResetAbort calls remainSYSLIB0006 pragma suppressions remainCancellationToken parameterCancellationTokenSource.CancelAfter or equivalentWaitHandle.WaitAny with token.WaitHandle or async alternatives| Pitfall | Solution |
|---|---|
Adding CancellationToken parameter but never checking it in long-running code | Insert token.ThrowIfCancellationRequested() at regular checkpoints in loops and between expensive operations. Cancellation only works if the code cooperates. |
| Not passing the token through the full call chain | Every async or long-running method in the chain must accept and forward the CancellationToken. If one method in the chain ignores it, cancellation stalls at that point. |
Expecting CancellationToken to interrupt blocking synchronous calls like Thread.Sleep or socket.Receive | These calls do not check the token. Replace Thread.Sleep(ms) with . Replace synchronous I/O with async overloads that accept a . |
Thread.Abort throws PlatformNotSupportedExceptionCancellationTokenThread.Abort is obsoleteThread.Interrupt is obsolete (added in .NET 9)Task.WaitAsync(CancellationToken) — cancellable waiting for task-based code (.NET 6+)Weekly Installs
48
Repository
GitHub Stars
725
First Seen
Mar 10, 2026
Security Audits
Gen Agent Trust HubPassSocketFailSnykPass
Installed on
github-copilot46
opencode46
kimi-cli44
gemini-cli44
amp44
cline44
TanStack Query v5 完全指南:React 数据管理、乐观更新、离线支持
2,500 周安装
WaitHandle.WaitAny with CancellationToken.WaitHandle, or async alternatives |
| ASP.NET request termination | Response.End or Response.Redirect(url, true) | Return from the action method; use HttpContext.RequestAborted |
| ThreadAbortException as control flow | Catch blocks that inspect ThreadAbortException to decide cleanup actions | Catch OperationCanceledException instead, with explicit cleanup |
| Thread.ResetAbort to continue execution | Catching the abort and calling ResetAbort to keep the thread alive | Check CancellationToken.IsCancellationRequested and decide whether to continue |
| Uncooperative code termination | Killing a thread running code that cannot be modified to check for cancellation | Move the work to a separate process and use Process.Kill |
Thread.Sleep(ms)Task.Delay(ms, token)token.WaitHandle.WaitOne(ms)ManualResetEvent.WaitOne()WaitHandle.WaitAny(new[] { event, token.WaitHandle })Response.End() entirely — just return from the method. Replace Response.Redirect(url, true) with Response.Redirect(url) (without the true endResponse parameter) or return a redirect result. In ASP.NET Core, use HttpContext.RequestAborted as the cancellation token for long-running request work.catch (ThreadAbortException) with catch (OperationCanceledException). Move cleanup logic to finally blocks or CancellationToken.Register callbacks. Do not catch OperationCanceledException and swallow it — let it propagate unless you have a specific recovery action.ResetAbort to prevent tearing down the thread. Check token.IsCancellationRequested after each unit and decide whether to continue. Create a new CancellationTokenSource (optionally linked to a parent token) for each new unit of work rather than trying to reset an existing one.CancellationToken (e.g., third-party library, native call), move the work to a child process. The host process communicates via stdin/stdout or IPC and calls Process.Kill if a timeout expires.CancellationTokenManualResetEventSlimSYSLIB0046Response.End() | Remove the call; return from the method |
Response.Redirect(url, true) | Response.Redirect(url) without endResponse, or return a redirect result |
#pragma warning disable SYSLIB0006 | Remove after replacing the Thread.Abort call |
token.WaitHandle.WaitOne(ms)CancellationTokenCatching OperationCanceledException and swallowing it | Let OperationCanceledException propagate to the caller. Only catch it at the top-level orchestration point where you decide what to do after cancellation (log, clean up, return a result). |
Not disposing CancellationTokenSource | CancellationTokenSource is IDisposable. Wrap it in a using statement or dispose it in a finally block. Leaking it causes timer and callback leaks. |
| Assuming cancellation is immediate | Cooperative cancellation only takes effect at the next checkpoint. If work items are large or the code has long gaps between checks, cancellation may be delayed. Design checkpoint frequency based on acceptable latency. |
Using Thread.Interrupt as a substitute for Thread.Abort | Thread.Interrupt is also not recommended in modern .NET. It only works on threads in WaitSleepJoin state and throws ThreadInterruptedException, which is a different exception type. Replace with CancellationToken signaling. |
Removing ThreadAbortException catch blocks without migrating the cleanup logic | ThreadAbortException catch blocks often contained critical cleanup (releasing locks, rolling back transactions). Move this logic to finally blocks or CancellationToken.Register callbacks before removing the catch. |