Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/294.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 取消并等待异步任务方法_C#_Asynchronous_Async Await_Task - Fatal编程技术网

C# 取消并等待异步任务方法

C# 取消并等待异步任务方法,c#,asynchronous,async-await,task,C#,Asynchronous,Async Await,Task,试图弄明白这一点,但找不到任何确定的东西 假设我有一个异步工作的类,可以动态启动或停止: class ModelObject { private CancellationTokenSource cts; private CancellationToken ct; private Progress<int> progress; private async Task DoSomething(IProgress<int> progres

试图弄明白这一点,但找不到任何确定的东西

假设我有一个异步工作的类,可以动态启动或停止:

class ModelObject
{
    private CancellationTokenSource cts;
    private CancellationToken ct;
    private Progress<int> progress;
    
    private async Task DoSomething(IProgress<int> progress)
    {
        ...
        
        while (DoingSomething)
        {
            if (ct.IsCancellationRequested)
            {
                await Task.Delay(10000); // Take our sweet time to cancel
                // Cancel work and return
            }
            
            ...
        }       
    }
    
    public async void StartAsync()
    {
        progress = new Progress<int>(...);
        cts = new CancellationTokenSource();
        ct = cts.Token;
        
        await DoSomething(progress);
    }
    
    public void Stop()
    {
        ct.Cancel();
        
        // HELP: await while DoSomething cancels
        
        // perform cleanup
    }
}
非常感谢您的帮助。

我不确定StartAsync方法为什么是异步的,因为除非调用Stop,否则它将无限期地执行。我的意思是,如果不采取其他行动,它将不会在某个时间点返回。我觉得在这个类中不需要异步 但如果有必要,我已经起草了可能会有所帮助的代码

    class ModelObject {
        private CancellationTokenSource cts;
        private CancellationToken ct;
        private Progress<int> progress;
        private Task doSomethingTask;
        private async Task DoSomething(IProgress<int> progress){
          ...
           while (DoingSomething)
           {
               if (ct.IsCancellationRequested)
               {
                   // Cancel work and return
               } 
            ...
           }       
        }

        public async void StartAsync () {
            progress = new Progress<int>(...);
            cts = new CancellationTokenSource ();
            ct = cts.Token;
            doSomethingTask = DoSomething (progress);
            await doSomethingTask;
        }

        public void Stop () {
            cts.Cancel();
            doSomethingTask.Wait();
        }
    }

虽然您可以等待DoSomething返回的任务,但也可以使用TaskCompletionSource


我倾向于向ModelObject类添加一个Completion属性。调用方可以选择在取消操作后等待或不等待完成。此外,我可能会对API的不当使用进行防范。在现有操作挂起时尝试启动新操作将导致异常

public Task Completion { get; private set; } = Task.CompletedTask;

public async void Start()
{
    if (_cts != null) throw new InvalidOperationException("Operation is in progress.");
    using (_cts = new CancellationTokenSource())
    {
        _ct = _cts.Token;
        _progress = new Progress<int>(/*...*/);
        this.Completion = DoSomethingAsync();
        try
        {
            await this.Completion;
        }
        catch { } // Ignore
        finally
        {
            _cts = null;
            _ct = default;
            _progress = null;
        }
    }
}

public void Stop()
{
    _cts?.Cancel();
}

只是一个小提示:异步void是不好的。它应该是异步任务。A在这里会很好。很难说清你在清理什么,所以很难提供解决方案。@Enigmativity Hi做了一个小改动,希望这能有所帮助。清理,如删除正在处理的文件等。您阅读了该页面吗?您当然没有提供任何类似的解决方案。如果答案不建议使用。请稍候,这将是一个完整的解决方案…感谢您的详细解释。我在Stop方法中执行清理的原因是因为我希望能够改变清理,例如停止、取消、暂停或其他操作的不同清理。我的目标是让剂量测量任务只关注实际任务,而不是处理清理。另外,Start方法应该只与启动任务有关。@antikbd在我的示例中,Start是async void,因此从调用方的角度来看,它只不过是启动任务。它还向任务附加了一个延续,以便在任务完成时更新类的内部状态,这一事实对调用方是透明的。关于对不同风格的站点进行不同的清理,您可以对每个站点使用不同的CT,或者使用一些额外的状态,如:public void Stop1{{u stopType=1;_CTS?.Cancel;}。谢谢。是的,这是我目前的方法-使用多个CancellationToken。但是,我希望我不必检查多个令牌,因为可能会出现错误,我可以只使用一个令牌和多个方法。@antikbd有不同的方法,所有这些方法都试图改变内部状态,希望调用方不会在错误的时间、多次或不正确的顺序调用它们,这对我来说似乎更容易出错! private TaskCompletionSource<object> tcs; private async Task DoSomething(IProgress<int> progress){ ... while (DoingSomething) { if (ct.IsCancellationRequested) { // Cancel work and return } ... } tcs.SetResult(null); } public async Task Stop () { cts.Cancel(); await tcs.Task; }
public Task Completion { get; private set; } = Task.CompletedTask;

public async void Start()
{
    if (_cts != null) throw new InvalidOperationException("Operation is in progress.");
    using (_cts = new CancellationTokenSource())
    {
        _ct = _cts.Token;
        _progress = new Progress<int>(/*...*/);
        this.Completion = DoSomethingAsync();
        try
        {
            await this.Completion;
        }
        catch { } // Ignore
        finally
        {
            _cts = null;
            _ct = default;
            _progress = null;
        }
    }
}

public void Stop()
{
    _cts?.Cancel();
}
private async Task DoSomethingAsync()
{
    try
    {
        while (doingSomething)
        {
            // Do some work
            _ct.ThrowIfCancellationRequested();
        }
    }
    catch (OperationCanceledException)
    {
        await Task.Delay(10000); // Take our sweet time to cancel
        throw; // Rethrow the exception
    }
    finally
    {
        // perform cleanup, whether successful, failed or canceled
    }
}