异步非轮询处置机制,用于等待所有方法调用在 .NET 5 C# 中完成



我经常发现我的组件具有公共异步(返回Task<T>)方法MDisposeCoreAsync。其他组件通过调用M来使用此组件。应用程序运行,并在某个时候调用关闭。停机是对所有组件的级联处置。假设执行M可能需要很长时间。那么问题就出现了,当调用DisposeCoreAsync时,一个或多个线程正在执行M并且位于其中的某个位置。我想找到一个原始(或简单机制)P,优先使用纯 .NET 5 库,这样我就可以写这样的东西:

public async Task<bool> M()
{
if (!P.Increment())
return false; // Shutdown detected
...
P.Decrement(); // Only after this happens for all active executions, disposal can finish
return result;
}
protected virtual async ValueTask DisposeCoreAsync()
{
...
P.Shutdown(); // This should prevent new P.Increment to succeed
await P.WaitAllFinishedAsync().ConfigureAwait(false);
// From here down we are guaranteed that no thread will ever execute the actual body of M().
...
}

因此,P.Increment应该增加一个主动处决M身体的计数器。P.Decrement递减计数器。P.Shutdown确保任何进一步的P.Increment尝试都失败。P.WaitAllFinishedAsync等到 P 的计数器变为 0。

如果我允许忙于等待,这一切都是微不足道的。我可以像Interlocked.Increment一样实现P.Increment,我可以像Interlocked.Decrement一样实现P.Decrement,我可以用一些非常高的位实现Interlocked.DecrementP.Shutdown,比如0x1000000。只有当递增新值为正时,P.Increment才会成功。然后我可以P.WaitAllFinishedAsync实现为while (P.counter > -0x1000000) Task.Delay(10);

但是,如何在不定期检查我们是否在那里的情况下正确地做到这一点WaitAllFinishedAsync呢?此外,如何以最小的开销执行M来做到这一点?它只是关闭机制,因此不应给频繁执行M带来沉重负担。

当然,我可能会使用using并在P.Dispose内部而不是P.Increment/Decrement中制作P.Decrement,以确保内部的任何异常或返回都不会忘记"释放"P,但这只是一个实现细节。

您要查找的基元是异步兼容的倒计时事件。BCL 中没有执行此操作的类型,但您可以自己生成一个类型。我这里有一个开源的,你可以用它来获得灵感。

相关内容

  • 没有找到相关文章

最新更新