Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/274.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

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.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#_Async Await_Task - Fatal编程技术网

C# 如果抛出异常,则取消所有异步方法

C# 如果抛出异常,则取消所有异步方法,c#,async-await,task,C#,Async Await,Task,我玩取消令牌,我想了解它是如何工作的。我有两个异步方法(在我的示例中是两个,但理论上我可以有100个)。 如果其中一个异步方法引发异常,我想取消所有异步方法中的工作 我的想法是在调用所有方法的异常情况下取消令牌。当一个令牌被取消时,我希望其他方法停止工作,但这并没有发生 using System; using System.Threading; using System.Threading.Tasks; namespace CancelationTest { class Program

我玩取消令牌,我想了解它是如何工作的。我有两个异步方法(在我的示例中是两个,但理论上我可以有100个)。 如果其中一个异步方法引发异常,我想取消所有异步方法中的工作

我的想法是在调用所有方法的异常情况下取消令牌。当一个令牌被取消时,我希望其他方法停止工作,但这并没有发生

using System;
using System.Threading;
using System.Threading.Tasks;

namespace CancelationTest
{
    class Program
    {
        static void Main(string[] args)
        {
            new Test();
            Console.ReadKey();
        }
    }

    public class Test
    {
        public Test()
        {
            Task.Run(() => MainAsync());
        }

        public static async Task MainAsync()
        {
            var cancellationTokenSource = new CancellationTokenSource();
            try
            {
                var firstTask = FirstAsync(cancellationTokenSource.Token);
                var secondTask = SecondAsync(cancellationTokenSource.Token);
                Thread.Sleep(50);
                Console.WriteLine("Begin");
                await secondTask;
                Console.WriteLine("hello");
                await firstTask;
                Console.WriteLine("world");
                Console.ReadKey();
            }
            catch (OperationCanceledException e)
            {
                Console.WriteLine("Main OperationCanceledException cancel");
            }
            catch (Exception e)
            {
                Console.WriteLine("Main Exception + Cancel");
                cancellationTokenSource.Cancel();
            }
        }

        public static async Task FirstAsync(CancellationToken c)
        {
            c.ThrowIfCancellationRequested();
            await Task.Delay(1000, c);
            Console.WriteLine("Exception in first call");
            throw new NotImplementedException("Exception in first call");
        }

        public static async Task SecondAsync(CancellationToken c)
        {
            c.ThrowIfCancellationRequested();
            await Task.Delay(15000, c);
            Console.WriteLine("SecondAsync is finished");
        }
    }
}
第二个方法完成工作并延迟任务15秒,即使第一个方法抛出异常也是如此

结果是什么:

开始

第一次调用中的异常

SecondAsync已完成

你好

主异常+取消

我希望secondAsync停止延迟并抛出OperationCancelException。 我预计会有这样的结果:

开始

第一次调用中的异常

主异常+取消

主操作取消异常取消

我哪里出错了? 为什么方法SecondAsync完全执行并且不引发异常?如果我更改SecondAsync和FirstAsync的顺序,则当令牌被取消时,Second method stop会延迟并引发异常。

您需要位于被调用的方法可以访问的范围内,并且您需要调用
CancellationTokenSource.Cancel()
以取消使用该源的所有操作


您还可以调用
CancellationTokenSource.CancelAfter(TimeSpan)
以在延迟时取消它。

,因为代码的相关部分是:

try
{
   ...
   await secondTask;
   await firstTask;
}
catch(...)
{
    source.Cancel();
}
现在,当第一个任务启动并抛出时,将在第二个任务之后等待它。在等待任务之前,异常不会出现在调用方中。因此,catch子句将仅在secondTask完成后执行。Cancel()发生得太晚了

如果你想让第一个任务打断第二个任务,你必须

  • 将源代码传递到FirstAsync并在那里调用Cancel()。有点难看
  • 改变等待结构。我觉得你的样品有点做作。使用Parallel.Invoke()或类似的方法,它会很自然地发生

  • 取消是合作的:您的任务必须定期检查令牌,这需要一个循环。@HenkHolterman OP将
    CancellationToken
    传递给
    Task.Delay
    。当令牌发出信号时,应该取消延迟吗?@PetSerAl-是的,我忽略了这一点。虽然文档对延迟取消的时间有点含糊不清,但我认为这里可能仍需要15秒。@Raskolnikov取消的方式不允许您预期的“订阅令牌取消事件”。。ThrowIfCancellationRequested只需检查是否请求了令牌取消,如果是,则抛出异常,如果不是,则不执行任何操作。如果在稍后阶段取消,它不会抛出。您也可以在请求取消时运行。它在两个方法的范围内,并且tr Main方法调用Cancel(),这究竟是如何回答问题的。引用:“我希望其他方法停止工作,但这不会发生”?它完全回答了这个问题。而且紧凑。通读代码。我的意思是答案太短了,如果你能添加更多关于“为什么其他方法停止工作”的解释就好了。。。也许我错了,但我不知道OP对ThrowIfCancellationRequested的看法,我不知道OP对ThrowIfCancellationRequested的看法,这其实并不重要。如何使用
    Parallel.Invoke
    async
    方法?