Q:

Exception handling in Boost. Asio when io_service is threaded

If an app has only one io_service object and is threaded (see code below), what happens if one of the async handlers throw an exception.  How does it propagate and more importantly whats the best way to handle them. 
std::list< boost::shared_ptr< the_client > > clients_list;
for(int i = 0; i < n_threads; i++)
{
    clients_list.insert(boost::make_shared< the_client >( io_service, server_host, server_port ));
}

for(unsigned int i = 0; i < n_threads; i++)
{
    threads.create_thread(boost::bind(&boost::asio::io_service::run, boost::ref(io_service)));
}

for(std::list< boost::shared_ptr< the_client > >::iterator itr = clients_list.begin(); itr ! = clients_list.end(); ++itr)
{
    (*itr)->connect_to_server_and_run_statemachine();
}

Here the_client::connect_to_server_and_run_statemachine() sets up the connection to server and initiates the async connection handling. 
I am aware of a question on a similar topic, but that doesn't consider the multi-threaded io_service scenario. 

A:

Nothing magical happens.  If you catch the exception somewhere, then your catch block handles it.  Otherwise, an uncaught exception terminates the process. 
How you should handle it depends on what you want to happen.  If the exception should never happen, then let it terminate the process.  If you want to eat or handle the exceptions, then write a function that wraps io_service::run in a try/catch block and have the threads run that instead. 
I don't like putting the intelligence that far from the code.  My preferred solution is to never have my asynchronous functions throw exceptions unless there's a truly fatal error.  If an asynchronous function knows how to handle an exception it might throw, then it should catch it. 
However, it is perfectly acceptable to wrap run if that makes sense in your application.