none
What's happen in task_handle & (structured_)task_group when a functor or lambda throw an exception RRS feed

  • Question

  • I play with PPL with the  CTP deliver at the PDC08 and I have code lke:

    task_handle<function<void(void)>> t = [&]() { throw new exception(); };

    task_group tg;

    tg.run(t);

    task_group_status status = tg.wait(); // actually statut is 0x001cf580
    // if I switch with structured_task_group, the statut value is "completed"


    Have you any explanation about that. Do you plan to provide a solution like managed world (aggregate task's exceptions in a dedicated collection) in future release.

    Bruno
    Friday, January 16, 2009 5:14 PM

Answers

  • Bruno,

    I'm very glad to hear you're looking at the CTP deeply enough to ask questions about the exception model.  We do try to keep the native and managed models consist and as you've noted exception handling is one of the key semantic differences between them.  We have discussed various extension points, but ultimately wanted to ensure that the cost of the task_group stayed very low and that the behavior is straightforward and explainable.

    Do you have a common use case for the aggregate exception, i.e. does it fit better in your application? if so I'd definitely like to hear more.  I'd also like to hear if the behavior is unclear or there are scenarios you feel you can't accomplish and I'd be glad to share some ways to extend task_group / task_handle to aggregate exceptions if desired.

    To explain what's going on here in the example you've provided...

    If an unhandled exception is encountered while running a task that is part of a task_group (or structured_task_group) then that exception will get packaged up as a std::exception_ptr and stored in the owning task_group, remaining work in the task_group is effectively canceled at this point so any tasks that haven't started yet won't get started and any currently running tasks can check the cancellation status.  task_group::wait will call std::rethrow_exception if there is an exception_ptr to rethrow. 

    So in this example 'status' is an unitialized enum, because tg.wait() throws an exception, note the following additional example, stat will be unitialized and 'canceling!' will hopefully be written to the console.

        task_group_status stat;  
        task_group tg;   
        task_handle<function<void(void)>> t = [&]() {  
            Sleep(100);  
            throw new exception();   
        };  
        task_handle<function<void(void)>> t2 = [&](){  
            Sleep(500);  
            if(tg.is_canceling())  
                printf("canceling!\n");  
        };  
        tg.run(t);  
        tg.run(t2);  
        stat = tg.wait(); 

    Rick Molloy Parallel Computing Platform : http://blogs.msdn.com/nativeconcurrency
    Saturday, January 17, 2009 8:44 AM

All replies

  • Bruno,

    I'm very glad to hear you're looking at the CTP deeply enough to ask questions about the exception model.  We do try to keep the native and managed models consist and as you've noted exception handling is one of the key semantic differences between them.  We have discussed various extension points, but ultimately wanted to ensure that the cost of the task_group stayed very low and that the behavior is straightforward and explainable.

    Do you have a common use case for the aggregate exception, i.e. does it fit better in your application? if so I'd definitely like to hear more.  I'd also like to hear if the behavior is unclear or there are scenarios you feel you can't accomplish and I'd be glad to share some ways to extend task_group / task_handle to aggregate exceptions if desired.

    To explain what's going on here in the example you've provided...

    If an unhandled exception is encountered while running a task that is part of a task_group (or structured_task_group) then that exception will get packaged up as a std::exception_ptr and stored in the owning task_group, remaining work in the task_group is effectively canceled at this point so any tasks that haven't started yet won't get started and any currently running tasks can check the cancellation status.  task_group::wait will call std::rethrow_exception if there is an exception_ptr to rethrow. 

    So in this example 'status' is an unitialized enum, because tg.wait() throws an exception, note the following additional example, stat will be unitialized and 'canceling!' will hopefully be written to the console.

        task_group_status stat;  
        task_group tg;   
        task_handle<function<void(void)>> t = [&]() {  
            Sleep(100);  
            throw new exception();   
        };  
        task_handle<function<void(void)>> t2 = [&](){  
            Sleep(500);  
            if(tg.is_canceling())  
                printf("canceling!\n");  
        };  
        tg.run(t);  
        tg.run(t2);  
        stat = tg.wait(); 

    Rick Molloy Parallel Computing Platform : http://blogs.msdn.com/nativeconcurrency
    Saturday, January 17, 2009 8:44 AM
  • We were chatting about this offline, in the CTP the  behaviour does in fact 'swallow' the exceptions as described by you, the marshalling and repackaging of exceptions which I described above is not in the CTP.
    Rick Molloy Parallel Computing Platform : http://blogs.msdn.com/nativeconcurrency
    Saturday, January 17, 2009 7:15 PM
  • Rick,

    Many thanks. Actually  even is_canceling property is not implemented in my CTP.
    About why I'm testing PPL deeply,  the answer is simple: I'll speak (in French) about Parallel Programming For C++ Developers In Dev10 for Microsoft TechDays in February 09. (http://galilee.microsoft.fr/TechDays2009/Session.aspx?CellID=c52ff7cb-5c39-4cae-8e73-1b6e06f915cb). And finally, I co-animate with Eric Vernié a Microsoft French blog "Développement parallèle": http://blogs.msdn.com/devpara/. It will be very kind if you send us your marvelous (PPL + Agent) sample ImageDemo to conclude my TechDays session :-)

    Bruno
    http://blogs.msdn.com/devpara/.
    boucard.bruno@free.fr

    Monday, January 19, 2009 11:19 AM