[C++-sig] question on boost.python exception mechanisms

Niall Douglas s_sourceforge at nedprod.com
Thu Apr 18 02:40:49 CEST 2013


On 17 Apr 2013 at 17:13, Holger Joukl wrote:

> // the global per-thread exception storage
> boost::unordered_map<pthread_t, boost::exception_ptr> exception_map;

You can't assume pthread_t is of integral type. You can a thread_t 
(from C11) I believe. You may not care on your supported platforms 
though.

>     throw std::runtime_error("throwing up");

If you're going to use Boost's exception_ptr implementation, you 
really ought to throw using Boost's exception throw macro. Otherwise 
stuff become unreliable.

> void guarded_callback_with_exception(cb_arg_t arg) {
>     std::cout << "--> guarded exception-throwing CPP callback" << arg <<
> std::endl;
>     try {
>         throw std::runtime_error("throwing up");
>     } catch (...) {
>         std::cout << "storing exception in exception map" << std::endl;
>         pthread_t current_thread = pthread_self();
>         exception_map[current_thread] = boost::current_exception();
>         exception_map.erase(current_thread);
>         //global_exception_holder = boost::current_exception();
>     }
>     std::cout << "<-- guarded exception-throwing CPP callback" << arg <<
> std::endl;
> }

If you're just going to do this, I'd suggest you save yourself some 
hassle and look into packaged_task which is a std::function combined 
with a std::future. It takes care of the exception trapping and 
management for you. Do bear in mind there is absolutely no reason you 
can't use a future within a single thread to traverse some state over 
third party binary blob code, indeed I do this in my own code at 
times e.g. if Qt, which doesn't like exceptions, stands between my 
exception throwing code at the end of a Qt signal and my code which 
called Qt.

>     pthread_t current_thread = pthread_self();
>     if (exception_map.find(current_thread) != exception_map.end()) {
>         try {
>             std::cout << "rethrowing exception from exception map" <<
> std::endl;
>             boost::rethrow_exception(exception_map[current_thread]);
>         } catch (const std::exception& exc) {
>             std::cout << "caught callback exception: " << exc.what() <<
> std::endl;
>         }
>     }

Why not using thread local storage?

> Which doesn't respect call function depth (how would I do that?)

Keep a count of nesting levels, so if a callback calls a callback 
which calls a callback etc.

> and doesn't use a queue; I suppose you mean using the lockfree queue for
> threadsafe
> access to the hash table.

Maybe a hash table of lockfree queues. Depends on your needs.

> I think I don't even need that for my use case as I basically
> - call dispatch on a Boost.Python wrapped object
> - which invokes the C libs dispatcher function
> - which invokes the registered callbacks (these will usually be implemented
> in Python)
> 
> i.e. the same thread that produced the exception will need to handle it.

Another possibly useful idea is to have the C libs dispatcher 
dispatch packaged_task's into a per-thread lock free queue which you 
then dispatch on control return when the C library isn't in the way 
anymore. Call it deferred callbacks :)

> Thanks for the valuable hints!

You're welcome.

Niall

-- 
Any opinions or advice expressed here do NOT reflect those
of my employer BlackBerry Inc.
Work Portfolio: http://careers.stackoverflow.com/nialldouglas/



-------------- next part --------------
A non-text attachment was scrubbed...
Name: SMime.p7s
Type: application/x-pkcs7-signature
Size: 6061 bytes
Desc: not available
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20130417/4c04ee5b/attachment-0001.bin>


More information about the Cplusplus-sig mailing list