IDisposable和Task.WaitAll等待自己

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

我有一个类,它使用Task.Run生成几个工作任务,并在集合中引用这些任务。此外,这个类实现IDisposable以便清理。在Dispose()的实施中,我使用Task.WaitAll(_listOfTasks)等待所有工人完成。

现在可能发生的事情是,对Dispose()的调用是来自其中一个工作任务,这显然会导致自Qazxswpoi等待自己的死锁。

是否有模式或推荐的方法来解决这种情况?或者还有其他方法可以确保在处理类时完成所有正在运行的任务吗?

WaitAll
c# .net task-parallel-library idisposable
1个回答
0
投票

有几种方法可以在.NET生态系统中使用public class Loader : IDisposable { private readonly IList<Task> _runningTasks = new List<Task>(); public Loader() { } public void Dispose() { Task.WaitAll(_runningTasks.ToArray()); } public void StartLoadAsync() { var task = Task.Run(() => DoSomeWork()); _runningTasks.Add(task); } void DoSomeWork() { // after doing some actual work here, call Dispose() in certain cases if (SomeCondition) { Dispose(); } } } 接口。我想展示其中两个在多线程/异步使用中特别相关的内容。

反应性扩展

订阅一个observable时,会返回一个IDisposable对象。这里接口用作取消触发器。没有线程关联,可以随时调用它。实施承诺尽力取消,但在取消最终发生时不予以保证。这意味着在IDisposable调用之后,订阅可能仍然有效一段时间。

Dispose

在即将推出的IAsyncEnumerator界面中,您将能够在检索枚​​举器时传递取消令牌。枚举器实现IAsyncEnumerable,应予以处置。枚举器不需要是线程安全的,即,当对另一个接口方法或返回的任务的调用仍在运行时,不允许调用IAsyncDisposable。如果要停止枚举,则必须使用取消令牌。

结论

区分取消和资源清理很重要。在您的情况下,您还可以使用取消令牌。由于您已经拥有围绕方法调用的所有内容,您可以选择添加DisposeAsync方法。如果你现在需要加载器实际终止,你可以实现Cancel接口:

IAsyncDisposable

如果你愿意,你可以从public void Cancel() => ...; public async ValueTask DisposeAsync() { // Cancel(); await Task.WhenAll(_runningTasks.ToArray()); } 方法调用Cancel。我不确定是否有任何最佳实践。我倾向于不在那里调用DisposeAsync,因为它为您或您的API用户提供了更多可能性。请注意,Cancel界面只有netstandard 2.1。但是,这不应该阻止你现在使用这种模式。

© www.soinside.com 2019 - 2024. All rights reserved.