【问题标题】:How to cancel SemaphoreSlim WaitAsync method如何取消 SemaphoreSlim WaitAsync 方法
【发布时间】:2021-12-22 12:48:47
【问题描述】:

考虑以下代码,使用.NET 5 执行:

using System;
using System.Threading;

public class Program
{
    public static void Main(string[] args)
    {
        var semaphore = new SemaphoreSlim(0);

        var cts = new CancellationTokenSource();

        var entrance = semaphore.WaitAsync(cts.Token);

        cts.Cancel();
        cts.Dispose();

        semaphore.Release();

        Console.WriteLine("Entrance status: " + entrance.Status);
        Console.WriteLine("Current count: " + semaphore.CurrentCount);
    }
}

当我运行此代码时,应用程序成功完成,我得到以下结果:

进入状态:WaitingForActivation

当前计数:0

但由于我在释放信号量之前取消了 WaitAsync 操作,因此我期望信号量 CurrentCount1 并且 Task 处于 Canceled 状态。

在发布问题之前,我在https://dotnetfiddle.net 中运行了代码,令人惊讶的是,它在.NET Framework 4.7.2 中运行得和我预期的一样。

我是否发现 .NET 5 SemaphoreSlim 中的错误?

有没有办法在.NET 5 中获得前一种行为?

PS:我找到了一种方法来通过设置WaitAsync 操作的超时来获得前一种行为,但这不是我认为可以接受的答案。

根据 Guru Stron cmets 进行编辑

Release 语句生成OperationCancelledException 之前等待entrance,正如我所期望的那样。

但是在语句之​​后等待不会抛出任何异常并且信号量被“消耗”了。

这两种情况都会在以前的.NET Framework 中产生错误。

【问题讨论】:

  • 如果您在Release 语句之后添加Console.WriteLine("Entrance status: " + entrance.Status);,它将报告Canceled 状态。
  • 等待任务也会抛出预期的错误。之后Status 也更改为预期。
  • @GuruStron:我在发布之前经常更改代码,以至于我犯了一个错误。在Release 语句之前等待将按预期生成OperationCancelledException,但在之后等待将成功完成。
  • 我希望这两种情况都会导致 OperationCancelledException,就像在 .NET 4.7.2 中一样。
  • 是的,也可以在 .NET 6 rc 中进行复制。检查状态两次使其成为需要的一次))

标签: c# .net-5 cancellationtokensource


【解决方案1】:

CancellationTokenSource.Cancel 是取消请求。取消令牌立即取消,但Cancel 确实保证等待,阻塞当前线程,直到所有监听该取消令牌的操作都被取消(及其父操作等)。

换句话说,您的代码有一个固有的竞争条件:ReleaseCancellationToken 的取消将首先到达WaitAsync 操作。如果Release首先到达它,那么信号量将被获取。如果取消先到达,则等待将被取消。

awaiting WaitAsync 操作的任务在调用 Release 之前通过 (a) 等待操作来解决此竞争条件,强制它在发送 Release 之前看到取消。

我是否发现 .NET 5 SemaphoreSlim 中的错误?

没有。该代码取决于 .NET Framework 和 .NET 5 上的竞争条件。不保证竞争条件的结果在任一平台上都有任何特定结果。

有没有办法在 .NET 5 中获得以前的行为?

没有。我建议重新编写代码,使其不依赖于竞争条件。然后它将在两个平台上正常工作。

可能代码将SemaphoreSlim 用于它不是为它设计的东西。例如,如果您需要一个异步工作队列,则构建一个异步工作队列,而不是尝试使用 SemaphoreSlim 作为一个。

【讨论】:

    猜你喜欢
    • 2015-11-09
    • 2014-07-28
    • 2017-11-02
    • 1970-01-01
    • 1970-01-01
    • 2012-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多