该解决方案基于使用Task ParallelLibrary时如何处理所有未处理的异常?
class Program{ static void Main(string[] args) {Program p = new Program();p.tpltestOne(); } public void tpltestOne() {//-------------------------------------------------MyClassHere.onUnobservedTaskException += (object sender, EventException e) =>{ Console.WriteLine(e.Exception.Message); //its fired OK};TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs e) =>{ Console.WriteLine(e.Exception.Message); // its not fired, buggy};//-------------------------------------------------CancellationTokenSource source = new CancellationTokenSource();Task tz = MyClassHere.CreateHandledTask( new TaskScheduled(0, () => {if (!source.IsCancellationRequested){ Console.WriteLine('A-main-task-started');}Thread.Sleep(5000);if (source.IsCancellationRequested){ Console.WriteLine('CancelingMainTask');} }) , new TaskScheduled(3000, () => { Console.WriteLine('okTaskCalled'); }) , null //new TaskScheduled(0, () => { Console.WriteLine('cancelTaskCalled'); }) , TaskCreationoptions.AttachedToParent , source.Token , new TaskScheduled(2000, () => {if (!source.IsCancellationRequested){ Console.WriteLine('B-timeout');} }) , new TaskScheduled(1000, () => {if (!source.IsCancellationRequested){ Console.WriteLine('C-timeout');}source.Cancel(); }));if(tz != null){ tz.ContinueWith(t => { Console.WriteLine('END'); });}Task tsk_1 = MyClassHere.createHandledTask(() =>{ double x = 1; x = (x + 1) / x;}, false);Task tsk_2 = MyClassHere.createHandledTask(() =>{ double y = 0; throw new Exception('forced_divisionbyzerodontthrowanymore_test'); // here -> System.Exception was unhandled by user code}, true);Task tsk_3 = MyClassHere.createHandledTask(() =>{ double z = 1; z = (z + 1) / z;}, true);Task tsk_4 = MyClassHere.createHandledTask(() =>{ double k = 1; k = (k + 1) / k;}, true);Console.ReadLine(); }}public class EventException : EventArgs{ public Exception Exception; public Task task; public EventException(Exception err, Task tsk) {Exception = err;task = tsk; }}public class TaskScheduled{ public int waitTime; public Action action; public DateTime datestamp; public bool isCalled = false; public TaskScheduled(int _waitTime, Action _action) {this.waitTime = _waitTime;this.action = _action; }}public static class MyClassHere{ public delegate void UnobservedTaskException(object sender, EventException e); public static event UnobservedTaskException onUnobservedTaskException; //------------------------------------------------- public static void waitForTsk(Task t) {try{ t.Wait();}catch (AggregateException ae){ ae.Handle((err) => {throw err; });} } //------------------------------------------------- public static void RaiseUnobsrvEvtForEachIfHappens(this Task task) {task.ContinueWith(t =>{ var aggException = t.Exception.Flatten(); foreach (var exception in aggException.InnerExceptions) {onUnobservedTaskException(task, new EventException(exception, task)); }},TaskContinuationoptions.OnlyOnFaulted); // not valid for multi task continuations } //------------------------------------------------- public static Task CreateHandledTask(Action action) {return CreateHandledTask(action, false); } public static Task CreateHandledTask(Action action, bool attachToParent) {Task tsk = null;tsk = CreateHandledTask(action, attachToParent, CancellationToken.None);return tsk; } public static Task CreateHandledTask(Action action, bool attachToParent, CancellationToken cancellationToken) {Task tsk = null;TaskCreationoptions atp = TaskCreationoptions.None;if (attachToParent) { atp = TaskCreationoptions.AttachedToParent; }tsk = CreateHandledTask(action, atp, cancellationToken);return tsk; } public static Task CreateHandledTask(Action action, TaskCreationoptions tco, CancellationToken cancellationToken) {Task tsk = null;tsk = Task.Factory.StartNew(action, cancellationToken, tco, TaskScheduler.Default);tsk.RaiseUnobsrvEvtForEachIfHappens();return tsk; } public static Task CreateHandledTask(TaskScheduled mainTask, TaskScheduled onSuccesstask, TaskScheduled onCancelationTask, TaskCreationoptions tco, CancellationToken cancellationToken, params TaskScheduled[] timeouts) {Task tsk = null;ManualResetEvent me = new ManualResetEvent(false);if (timeouts == null || timeouts.Length < 1 || timeouts[0] == null){ tsk = CreateHandledTask(mainTask.action, tco, cancellationToken); me.Set();}else{ bool isCancelation = false; bool isSuccess = true; Task NonBlockCtxTask = CreateHandledTask(() => {tsk = CreateHandledTask(mainTask.action, tco, cancellationToken);me.Set();int qtdt = timeouts.Count(st => st.action != null);CountdownEvent cde_pas = new CountdownEvent(3);CountdownEvent cde_pat = new CountdownEvent(qtdt);Parallel.ForEach<TaskScheduled>(timeouts, (ts) =>{ try {bool itsOnTime = tsk.Wait(ts.waitTime, cancellationToken);cde_pat.Signal();if (!itsOnTime){ isSuccess = false; Task tact = CreateHandledTask(ts.action, TaskCreationoptions.None, cancellationToken);} } catch (OperationCanceledException oce) {isSuccess = false;cde_pat.Signal(cde_pat.CurrentCount);isCancelation = true; }});try{ isSuccess &= cde_pat.Wait(System.Threading.Timeout.Infinite, cancellationToken) && !isCancelation;}catch (OperationCanceledException oce){ isCancelation = true; isSuccess = false;}finally{ cde_pas.Signal();}try{ if (isCancelation && onCancelationTask != null) {Thread.Sleep(onCancelationTask.waitTime);Task tcn = CreateHandledTask(onCancelationTask.action); }}catch { }finally { cde_pas.Signal();}try{ if (isSuccess && onSuccesstask != null) {Thread.Sleep(onSuccesstask.waitTime);Task tcn = CreateHandledTask(onSuccesstask.action); }}catch { }finally{ cde_pas.Signal();}cde_pas.Wait(System.Threading.Timeout.Infinite); }, TaskCreationoptions.None, cancellationToken); }me.WaitOne();return tsk; } //-------------------------------------------------}解决方法
这个问题已经在这里有了答案 :
使用任务并行库时如何处理所有未处理的异常? (3个答案)
去年关闭。
我在TPL编程方面遇到问题。我正在收到UnobservedTaskException,我在 [http://stackoverflow.com/questions/7883052/a-tasks-exceptions-were-not-observed-by-by-waiting-on-the-task-or-accessi 上使用@h4165f8ghd4f854d6f8h解决方案/ 11830087#11830087]处理异常,但仍会出现UnobservedTaskException。我也将以下代码放在启动任务之前:
TaskScheduler.UnobservedTaskException += (sender,e) => {e.SetObserved();throw e.Exception; };
但是[ http://stackoverflow.com/questions/10874068/exception-thrown-in-task-thread-not-caught-by-unobservedtaskexception]告诉它没有捕获每个TPL未处理的异常。
我想要气泡异常,直到到达堆栈顶部,然后对其进行处理。有人可以帮助我吗?
@乔恩·斯基特
嗨,我做了较小的可能现在编辑,谢谢
class Program{ static void Main(string[] args) {Program p = new Program();p.tplTestOne(); } public void tplTestOne() {TaskScheduler.UnobservedTaskException += (sender,e) =>{ e.SetObserved(); throw e.Exception;};Task tsk_1 = MyClassHere.createHandledTask(() =>{ double x = 1; x = (x + 1) / x;},false);Task tsk_2 = MyClassHere.createHandledTask(() =>{ double y = 0; throw new Exception('forced_divisionbyzerodontthrowanymore_test'); // here -> System.Exception was unhandled by user code},true);Task tsk_3 = MyClassHere.createHandledTask(() =>{ double z = 1; z = (z + 1) / z;},true);Task tsk_4 = MyClassHere.createHandledTask(() =>{ double k = 1; k = (k + 1) / k;},true);Console.ReadLine(); }}public static class MyClassHere{ public static void waitForTsk(Task t) {try{ t.Wait();}catch (AggregateException ae){ ae.Handle((err) => {throw err; });} } public static void throwFirstExceptionIfHappens(this Task task) {task.ContinueWith(t =>{ var aggException = t.Exception.Flatten(); foreach (var exception in aggException.InnerExceptions) {throw exception; // throw only first,search for solution }},TaskContinuationOptions.OnlyOnFaulted); // not valid for multi task continuations } public static Task createHandledTask(Action action) {return createHandledTask(action,false); } public static Task createHandledTask(Action action,bool attachToParent) {Task tsk = null;if (attachToParent){ TaskCreationOptions atp = TaskCreationOptions.AttachedToParent; tsk = Task.Factory.StartNew(action,atp);}else{ tsk = Task.Factory.StartNew(action);}tsk.throwFirstExceptionIfHappens();return tsk; }}
谢谢