确保 dotnet 任务在超出垃圾收集器范围时停止

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

我有一个后台任务,正在使用

Task
进行建模,并使用
IAsyncDisposable
停止。

// implementation
public sealed class Worker : IAsyncDisposable
{
    private readonly CancellationTokenSource _cts;
    private readonly Task _worker;

    public Worker()
    {
        _cts = new CancellationTokenSource();
        _worker = DoWork(_cts.Token);
    }

    public ValueTask DisposeAsync()
    {
        _cts.Cancel();
        _cts.Dispose();
        return new ValueTask(_worker);
    }

    private static async Task DoWork(CancellationToken token)
    {
        while (!token.IsCancellationRequested)
        {
            do async work
        }
    }
}

static async Task CorrectUsage()
{
    await using var worker = new Worker();

    do more stuff
}

static async Task IncorrectUsage()
{
    var worker = new Worker();

    do more stuff
}

在正常情况下,这工作得很好,但是,在我看来,如果调用代码不处理worker

,则可能会发生内存泄漏。如果 Worker
 组件被滥用,我希望 GC 在通过 
_cts.Cancel()
 调用超出范围时终止正在运行的任务。
我已经阅读过有关

~Worker()

Dispose(bool disposing)
的内容,但我找到的所有文档都指出这些方法专门用于处置非托管资源。

Q1:如何让GC调用
    _cts.Cancel()
  • Q2:如果答案包括 
  • Dispose(bool disposing)
  • 的使用,是否有任何文档说明如何使用
    disposing: false
    调用它?
    
    
  • 关于任务和 GC 的说明
.NET 任务实例在运行期间是否会超出范围?

c# .net task-parallel-library idisposable finalizer
1个回答
0
投票
如何让 GC 调用
_cts.Cancel()


像这样:

public sealed class Worker : IAsyncDisposable { ~Worker() { _cts.Cancel(); } public ValueTask DisposeAsync() { _cts.Cancel(); _cts.Dispose(); GC.SuppressFinalize(this); return new ValueTask(_worker); } }

如果 
_cts.Cancel()

被释放,则

_cts
会抛出异常。
GC.SuppressFinalize(this)
行确保不会调用
~Worker
终结器,从而防止出现此异常。
顺便说明一下,此 

DisposeAsync()

实现异步公开

_worker
任务的异常(如果有)。这违背了 C# 社区的集体智慧,根据集体智慧,
Dispose
/
DisposeAsync
不应该抛出异常

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