有什么安全的方法可以同步等待与取消?

问题描述 投票:0回答:1

我正在编写一个.NET标准2.0库,该库将具有相同功能的同步和异步版本,其中一个功能需要支持取消的延迟。

我试图想出一种方法来等待一个特定的时间,在所有的场景下都不会出现死锁或其他障碍。一个担心是 在异步方法上同步等待会导致死锁。.

考虑到这个类,你应该如何实现 Wait 以使其在任何地方都安全?呼叫 WaitAsync 不是需求,等待完全可以单独实现。

class Waiter
{
    // Easy enough
    public async Task WaitAsync(TimeSpan delay, CancellationToken token = default)
    {
        try
        {
            await Task.Delay(delay, token)
        }
        catch(OperationCancelledException)
        {
        }
    }

    // Not so straightforward
    public void Wait(TimeSpan delay, CancellationToken token = default)
    {
        WaitAsync(delay, token).GetAwaiter().GetResult(); // May deadlock
        WaitAsync(delay, token).Wait();                   // May deadlock, also doesn't propagate exceptions properly
        WaitAsync(delay).Wait(token);                     // Even worse
        Thread.Sleep(delay)                               // Doesn't support cancellation
        token.WaitHandle.WaitOne(delay, true);            // Maybe? Not sure how the second parameter works when I have no control over the context
        token.WaitHandle.WaitOne(delay, false);           // No idea
    }
}
c# .net delay deadlock cancellation
1个回答
0
投票

这个答案 几乎 回答了你所有的问题。具体来说,它解释了通过让其中一个调用另一个来实现同步和异步API不是一个好主意。如果你遇到了这种情况,我推荐你使用 布尔论点黑客.

对于你的具体问题,理想情况下,你会使用一个同步等待(Thread.Sleep),但由于它不支持 CancellationToken 这不是一个选项。所以你需要自己写。正如你问题中提到的。WaitHandle 有一个你可以使用的超时参数。

public void Wait(TimeSpan delay, CancellationToken token = default)
{
  token.WaitHandle.WaitOne(delay);
}

值得一看的是,你可以使用 波利 处理这个问题,事实上,他们实现了他们的 同步可取消延迟 这样一来,。

public static Action<TimeSpan, CancellationToken> Sleep = (timeSpan, cancellationToken) =>
{
  if (cancellationToken.WaitHandle.WaitOne(timeSpan))
    cancellationToken.ThrowIfCancellationRequested();
};
© www.soinside.com 2019 - 2024. All rights reserved.