2
votes

I'm having problems with TPL programming.
I'm getting UnobservedTaskException while using @h4165f8ghd4f854d6f8h solution on [ http://stackoverflow.com/questions/7883052/a-tasks-exceptions-were-not-observed-either-by-waiting-on-the-task-or-accessi/11830087#11830087 ] to handle exceptions but still getting UnobservedTaskException.
I added the following code before starting tasks too:

    TaskScheduler.UnobservedTaskException += (sender, e) =>
    {
        e.SetObserved();
        throw e.Exception;
    };  

but [ http://stackoverflow.com/questions/10874068/exception-thrown-in-task-thread-not-caught-by-unobservedtaskexception ] telling it won't catch every TPL unhandled exception.

I want propagate exceptions until reach top of stack then deal with it.
Can someone help me????


@Jon Skeet

Hi, I did a smaller repro, thanks for checking

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;
    }

}
    

Thanks

1
That doesn't demonstrate the problem on my box... it just runs. What are you seeing?Jon Skeet
Hi, thanks for see. Its worst there than here then because silent an Exception on that line : throw new Exception("forced_divisionbyzerodontthrowanymore_test"); // here -> System.Exception was unhandled by user code . Im getting this exception on Visual Studio 2010 enviroment: System.Exception was unhandled by user codenewway
Ah - I'm using .NET 4.5, which has different behaviour...Jon Skeet
Using 4.0 By the way, 4.5 ignore Exceptions ?newway
You should see ito too: stackoverflow.com/questions/4238345/…user1595458

1 Answers

1
votes

The solution was based on How to handle all unhandled exceptions when using Task Parallel Library?

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;
    }
    //-------------------------------------------------
}