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

SemaphoreSlim中Wait、Release与CancellationToken的正确处理方式

SemaphoreSlim 取消时避免错误调用 Release 的正确方案

问题核心:当CancellationToken触发取消时,SemaphoreSlim.Wait或WaitAsync会直接抛出OperationCanceledException,此时程序并未成功获取信号量,若在finally里无条件调用Release,会触发SemaphoreFullException;而用空try/catch吞掉异常属于不良编码习惯,直接检查cancellationToken.IsCancellationRequested又存在竞态风险。

正确的处理方式是仅在确认成功获取信号量后,才调用Release,可以通过一个布尔标记变量实现:

同步场景代码示例

using var semaphoreSlim = new SemaphoreSlim(1, 1);
// 多线程共享的代码逻辑
var isSemaphoreAcquired = false;
try
{
    semaphoreSlim.Wait(cancellationToken);
    // 只有Wait执行成功未被取消,才标记为已获取
    isSemaphoreAcquired = true;
    
    // 此处执行需要同步保护的操作
}
catch (OperationCanceledException)
{
    // 可选:添加自定义取消处理逻辑
    throw; // 如需向上传递取消异常,保留此语句;否则可移除
}
finally
{
    // 仅在成功获取信号量时才释放
    if (isSemaphoreAcquired)
    {
        semaphoreSlim.Release();
    }
}

异步场景代码示例

using var semaphoreSlim = new SemaphoreSlim(1, 1);
// 多线程/多任务共享的异步代码逻辑
var isSemaphoreAcquired = false;
try
{
    await semaphoreSlim.WaitAsync(cancellationToken).ConfigureAwait(false);
    // 只有WaitAsync执行成功未被取消,才标记为已获取
    isSemaphoreAcquired = true;
    
    // 此处执行需要同步保护的异步操作
}
catch (OperationCanceledException)
{
    // 可选:添加自定义取消处理逻辑
    throw; // 如需向上传递取消异常,保留此语句;否则可移除
}
finally
{
    // 仅在成功获取信号量时才释放
    if (isSemaphoreAcquired)
    {
        semaphoreSlim.Release();
    }
}

方案原理

通过isSemaphoreAcquired布尔变量明确标记信号量是否成功被获取:

  • 只有当Wait/WaitAsync完整执行完毕(未被取消),才会将变量设为true
  • finally块仅在变量为true时调用Release,从根源上避免了未获取信号量就释放的错误,既不需要空catch吞异常,也不存在竞态问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 04:35:20