You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SemaphoreSlim的WaitAsync取消问题及.NET5与.NET Framework行为差异

结论

这不是.NET 5 SemaphoreSlim 的bug,是.NET Core 3.0及后续版本(包括.NET 5+)针对SemaphoreSlim的性能优化导致的行为变更,和.NET Framework的实现逻辑存在差异。

行为差异原因
  • .NET Framework中,SemaphoreSlim.WaitAsync(CancellationToken)在取消令牌触发时,会立刻将对应的等待请求从内部等待队列中移除,后续调用Release()时不会匹配到已取消的请求,因此信号量计数会加1,等待任务状态也会立刻标记为Canceled,和你的预期一致。
  • .NET Core 3.0及之后的版本,为了降低高并发场景下无超时WaitAsync调用的性能开销,调整了实现逻辑:取消令牌触发时不会主动从队列中删除等待项,而是等到Release()唤醒该等待项时,才会校验取消状态。你测试时打印状态的时机是在Release()之后、等待任务被调度校验之前,因此任务还保持WaitingForActivation状态,同时你释放的信号量刚好被这个未被移除的等待项占用,所以CurrentCount为0。
补充现象解释
  • 在Release()前await entrance:会主动触发取消状态校验,等待项会被从队列中移除,同时抛出OperationCanceledException,符合你的预期。
  • 在Release()后await entrance:等待项已经被Release()唤醒,调度时检测到虽然令牌已取消,但已经成功获取到信号量,因此不会抛出取消异常,信号量被正常消耗,这是新版逻辑的正常表现。
复现.NET Framework行为的方案

不需要使用额外的hack,官方提供了兼容实现:

  1. 调用带超时参数的WaitAsync重载,显式传入无限超时即可:semaphore.WaitAsync(Timeout.Infinite, cts.Token)。带超时参数的重载保留了旧版的实现逻辑,取消时会立刻从队列移除等待项,这就是你之前测试加超时参数就符合预期的原因,该方案是官方支持的兼容方案,可放心使用。
  2. 如果不想使用超时重载,可在取消令牌触发后、调用Release()前,主动await等待任务并捕获取消异常,确保等待项被提前从队列中移除,后续释放的信号量就不会被消耗,示例代码如下:
using System;
using System.Threading;
using System.Threading.Tasks;

public class Program
{
    public static async Task Main(string[] args)
    {
        var semaphore = new SemaphoreSlim(0);
        var cts = new CancellationTokenSource();
        var entrance = semaphore.WaitAsync(cts.Token);
        cts.Cancel();
        
        // 主动等待取消生效
        try
        {
            await entrance;
        }
        catch (OperationCanceledException)
        {
            // 忽略预期的取消异常
        }
        
        cts.Dispose();
        semaphore.Release();
        
        Console.WriteLine("Entrance status: " + entrance.Status);
        Console.WriteLine("Current count: " + semaphore.CurrentCount);
    }
}

上述代码运行后会输出你预期的结果:

Entrance status: Canceled
Current count: 1

内容的提问来源于stack exchange,提问作者fharreau

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 13:36:03