C#从CancellationToken.Register内部抛出操作CanceledException

C#从CancellationToken.Register内部抛出操作CanceledException,c#,.net,multithreading,cancellation,C#,.net,Multithreading,Cancellation,我有一个长时间运行的操作,我想在5秒后取消。不幸的是,IsCancellationRequested的轮询是不可能的(说来话长) 我使用下面的代码在取消回调中抛出OperationCanceledException。我想在主线程中捕获异常并进行处理,以便完全退出应用程序 这似乎无法正常工作,因为这会导致未处理的异常,并且应用程序不会正常终止 感谢您的帮助。谢谢 void TestTimeOut() { var cts = new CancellationToken

我有一个长时间运行的操作,我想在5秒后取消。不幸的是,IsCancellationRequested的轮询是不可能的(说来话长)

我使用下面的代码在取消回调中抛出OperationCanceledException。我想在主线程中捕获异常并进行处理,以便完全退出应用程序

这似乎无法正常工作,因为这会导致未处理的异常,并且应用程序不会正常终止

感谢您的帮助。谢谢

    void TestTimeOut()
    {
        var cts = new CancellationTokenSource();
        cts.CancelAfter(5000);

        try
        {
            var task = Task.Run(() => LongRunningOperation(cts.Token));
            task.ContinueWith(t => Console.WriteLine("Operation cancelled"), TaskContinuationOptions.OnlyOnFaulted);
            task.Wait();
        }
        catch (AggregateException e)
        {
            //Handle
        }
    }


    void LongRunningOperation(CancellationToken token)
    {
        CancellationTokenRegistration registration = token.Register(
            () =>
            {
                throw new OperationCanceledException(token); 
            });

        using (registration)
        {
            // long running operation here
        }
    }

您正在捕获一个
aggregateeexception
,但实际上抛出了一个
OperationCanceledException
,该异常将不会被捕获

更改以捕获所有类型的异常,例如

catch (Exception ex) { ... }

解决

您的代码中有很多禁忌,但我猜您只是将其用作解决问题的演示。 解决方案是
TaskCompletionSource
,我的演示也很难看,Task.Run()的层次太多,如果使用异步,应该一直异步。所以不要在PRD中使用它,自己研究
TaskCompletionSource
并找出更好的解决方案

    static void LongRunningOperation(CancellationToken token)
    {
        TaskCompletionSource<int> tcs1 = new TaskCompletionSource<int>();
        token.Register(() => { tcs1.TrySetCanceled(token); });
        Task.Run(() =>
        {
            // long running operation here
            Thread.Sleep(10000);
            tcs1.TrySetResult(0);
        }, token);
        tcs1.Task.Wait();
    }
静态void LongRunningOperation(CancellationToken令牌)
{
TaskCompletionSource tcs1=新的TaskCompletionSource();
token.Register(()=>{tcs1.trysetconceled(token);});
Task.Run(()=>
{
//长期运行的操作在这里
睡眠(10000);
tcs1.TrySetResult(0);
},代币);
tcs1.Task.Wait();
}

如果你
等待()
它,那么在任务中运行它有什么意义?
CancellationToken
的使用是合作的。如果您没有实际使用异步功能(Wait关键字),也许您可以创建一个线程。@DennisKuypers Task.Wait()之后还需要做其他事情,但前提是长时间运行的任务完成。否则,我希望捕获已取消的异常,进行一些整理并退出应用程序。我的观点是-如果您正在使用
Task.Wait()
进行阻止,为什么还要麻烦将其放在其他线程上?如果在后台线程上运行长时间运行的东西+阻塞调用线程与只在调用线程上运行工作没有区别thread@DennisKuypers因为我需要任务超时,所以我使用了CancelAfter。我确实尝试过异步/等待。。。但这里的主要问题是如何从任务中正确抛出OperationCanceledException。您能否提供有关长时间运行的操作的更多信息?也许可以将取消添加到它中(或者它提供了一种实际中止操作的机制)。感觉问题应该是关于手术以及如何正确地阻止它而不是杀死它。