"ThrowIfCancellationRequested"能不被TaskScheduler_UnobservedTaskException抓到吗?
Can "ThrowIfCancellationRequested" not be caught by TaskScheduler_UnobservedTaskException?
我有一个非常非常奇怪的问题,现在这是我的代码:
namespace TaskParallelTest
{
using System.Threading;
using System.Threading.Tasks;
using System;
using System.IO;
public class Program
{
static Program()
{
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
}
private static void DoPrint(int id, CancellationToken cToken)
{
Thread.Sleep(100);
if (!cToken.IsCancellationRequested)
{
Console.WriteLine("Id is:" + id + ";Current State:" + cToken.IsCancellationRequested);
cToken.Register(() => Console.WriteLine("Rollback for:" + id));
}
}
static void Main(string[] args)
{
CancellationTokenSource cTokenSource = new CancellationTokenSource();
Task.Run(() =>
{
for (int i = 1; i < 6; i++)
{
cTokenSource.Token.ThrowIfCancellationRequested();
DoPrint(i, cTokenSource.Token);
}
}, cTokenSource.Token);
Random r = new Random();
Thread.Sleep(400);
cTokenSource.Cancel(true);
Thread.Sleep(10000);
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("OK");
Console.ReadLine();
}
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
File.WriteAllText("C:\Resume\Error.txt", e.Exception.StackTrace);
e.SetObserved();
}
}
}
气死我的是为什么"UnobservedTaskException"的事件抓不到?我用了GC.Collect()和Thread.Sleep(),但是没有任何帮助……?
有时 "Error.txt" 没有创建,有时创建的文件什么也没有......?
【已解决——现在根据提示给出答案】
1) 请注意,我应该删除 "Cancellation" 并在此处模拟异常:
static void Main(string[] args)
{
CancellationTokenSource cTokenSource = new CancellationTokenSource();
Task.Run(() =>
{
for (int i = 1; i < 6; i++)
{
if (i==5)
{
throw new Exception("Error occured!");
}
DoPrint(i, cTokenSource.Token);
}
},cTokenSource.Token)
.ContinueWith
(
t =>
{
Console.WriteLine("Error has happened now.");
Console.WriteLine(t.IsFaulted);
},
TaskContinuationOptions.OnlyOnFaulted
);
Thread.Sleep(400);
//cTokenSource.Cancel();
//Thread.Sleep(2000);
GC.Collect();
GC.WaitForPendingFinalizers();
//Thread.Sleep(6000);
Console.WriteLine("OK");
Console.ReadLine();
}
2) 然后展平异常(因为这是一个聚合异常):
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
foreach (var item in e.Exception.Flatten().InnerExceptions)
{
Console.WriteLine(item.StackTrace);
}
e.SetObserved();
}
如果针对特定令牌抛出 OperationCanceledException
,并且这与您在创建任务时传递的令牌相同 - 它不会被视为 unhandled\unobserved 异常,因为它只是正常的预期取消流程.此异常只会将任务状态设置为已取消。你的情况也是如此:
var task = Task.Run(() =>
{
for (int i = 1; i < 6; i++)
{
// this exception is associated with cTokenSource.Token
cTokenSource.Token.ThrowIfCancellationRequested();
DoPrint(i, cTokenSource.Token);
}
}, cTokenSource.Token); // and this is the same token you pass when creating a task
如果不是这种情况(例如,您在创建任务时传递了不同的令牌)- 异常将被 UnobservedTaskException 处理程序拦截。
问题是:您为什么要将此异常视为未观察到?您希望任务可以取消,然后您取消它,它现在处于 Canceled 状态。没有 unobserved\unhandled.
我有一个非常非常奇怪的问题,现在这是我的代码:
namespace TaskParallelTest
{
using System.Threading;
using System.Threading.Tasks;
using System;
using System.IO;
public class Program
{
static Program()
{
TaskScheduler.UnobservedTaskException += TaskScheduler_UnobservedTaskException;
}
private static void DoPrint(int id, CancellationToken cToken)
{
Thread.Sleep(100);
if (!cToken.IsCancellationRequested)
{
Console.WriteLine("Id is:" + id + ";Current State:" + cToken.IsCancellationRequested);
cToken.Register(() => Console.WriteLine("Rollback for:" + id));
}
}
static void Main(string[] args)
{
CancellationTokenSource cTokenSource = new CancellationTokenSource();
Task.Run(() =>
{
for (int i = 1; i < 6; i++)
{
cTokenSource.Token.ThrowIfCancellationRequested();
DoPrint(i, cTokenSource.Token);
}
}, cTokenSource.Token);
Random r = new Random();
Thread.Sleep(400);
cTokenSource.Cancel(true);
Thread.Sleep(10000);
GC.Collect();
GC.WaitForPendingFinalizers();
Console.WriteLine("OK");
Console.ReadLine();
}
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
File.WriteAllText("C:\Resume\Error.txt", e.Exception.StackTrace);
e.SetObserved();
}
}
}
气死我的是为什么"UnobservedTaskException"的事件抓不到?我用了GC.Collect()和Thread.Sleep(),但是没有任何帮助……?
有时 "Error.txt" 没有创建,有时创建的文件什么也没有......?
【已解决——现在根据提示给出答案】
1) 请注意,我应该删除 "Cancellation" 并在此处模拟异常:
static void Main(string[] args)
{
CancellationTokenSource cTokenSource = new CancellationTokenSource();
Task.Run(() =>
{
for (int i = 1; i < 6; i++)
{
if (i==5)
{
throw new Exception("Error occured!");
}
DoPrint(i, cTokenSource.Token);
}
},cTokenSource.Token)
.ContinueWith
(
t =>
{
Console.WriteLine("Error has happened now.");
Console.WriteLine(t.IsFaulted);
},
TaskContinuationOptions.OnlyOnFaulted
);
Thread.Sleep(400);
//cTokenSource.Cancel();
//Thread.Sleep(2000);
GC.Collect();
GC.WaitForPendingFinalizers();
//Thread.Sleep(6000);
Console.WriteLine("OK");
Console.ReadLine();
}
2) 然后展平异常(因为这是一个聚合异常):
private static void TaskScheduler_UnobservedTaskException(object sender, UnobservedTaskExceptionEventArgs e)
{
foreach (var item in e.Exception.Flatten().InnerExceptions)
{
Console.WriteLine(item.StackTrace);
}
e.SetObserved();
}
如果针对特定令牌抛出 OperationCanceledException
,并且这与您在创建任务时传递的令牌相同 - 它不会被视为 unhandled\unobserved 异常,因为它只是正常的预期取消流程.此异常只会将任务状态设置为已取消。你的情况也是如此:
var task = Task.Run(() =>
{
for (int i = 1; i < 6; i++)
{
// this exception is associated with cTokenSource.Token
cTokenSource.Token.ThrowIfCancellationRequested();
DoPrint(i, cTokenSource.Token);
}
}, cTokenSource.Token); // and this is the same token you pass when creating a task
如果不是这种情况(例如,您在创建任务时传递了不同的令牌)- 异常将被 UnobservedTaskException 处理程序拦截。
问题是:您为什么要将此异常视为未观察到?您希望任务可以取消,然后您取消它,它现在处于 Canceled 状态。没有 unobserved\unhandled.