2

我在 TPL 编程方面遇到问题。
我在[ http://stackoverflow.com/questions/7883052/a-tasks-exceptions-were-not-observed-either-by-waiting-on-the-task-or-上使用 @h4165f8ghd4f854d6f8h 解决方案时收到 UnobservedTaskException accessi/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;
    }

}
    

谢谢

4

1 回答 1

1

该解决方案基于如何在使用任务并行库时处理所有未处理的异常?

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;
    }
    //-------------------------------------------------
}
于 2012-08-10T19:40:47.403 回答