c# - 与取消同步等待的安全方法是什么?
问题描述
我正在编写一个 .NET Standard 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
}
}
解决方案
这个答案 几乎回答了你所有的问题。具体来说,它解释了通过一个调用另一个来实现同步和异步 API 并不是一个好主意。如果您处于这种情况,我建议使用布尔参数 hack。
对于您的具体问题,理想情况下您会使用同步等待 ( Thread.Sleep
),但由于它不支持CancellationToken
这不是一个选项。所以你需要自己写。如您的问题所述,WaitHandle
有一个可以使用的超时参数:
public void Wait(TimeSpan delay, CancellationToken token = default)
{
token.WaitHandle.WaitOne(delay);
}
值得看看Polly是如何处理这个问题的,事实上,他们以这种方式实现了同步可取消延迟:
public static Action<TimeSpan, CancellationToken> Sleep = (timeSpan, cancellationToken) =>
{
if (cancellationToken.WaitHandle.WaitOne(timeSpan))
cancellationToken.ThrowIfCancellationRequested();
};
推荐阅读
- android - ActivityView的剪辑内容
- python - 如何在 Pandas 的 lambda 函数中使用 str.replace?
- r - 随机生成具有指定聚类系数的网络
- c++ - 转换罗马数字阿拉伯形式的基本程序?
- algorithm - Search first appearence in matrix under time complexity demands
- ios - 我怎么知道 Instagram 按钮已被选中?
- label - Vue-Chartjs onComplete 自定义标签 - 防止闪烁
- android - React Native api 在物理 Android 设备上不起作用(错误:网络错误)
- powershell - 使用 -eq 或 -ne 在 Powershell 中检测变音符号
- php - Telegram Inline Bot 不会显示