//Copyright (c) 2018 Emil Dotchevski //Copyright (c) 2018 Second Spectrum, Inc. //Distributed under the Boost Software License, Version 1.0. (See accompanying //file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) //This is a simple program that demonstrates the use of LEAF to transport error info between threads, //without using exception handling. See transport_eh.cpp for the exception-handling variant. #include #include #include #include #include #include namespace leaf = boost::leaf; //Define several error info types. struct failed_thread_id { std::thread::id value; }; struct failure_info1 { std::string value; }; struct failure_info2 { int value; }; struct failure_info3 { long value; }; struct failure_info4 { float value; }; //A type that represents a successfully returned result from a task. struct task_result { }; //This is a test task which succeeds or fails depending on its argument. leaf::result task( bool succeed ) { if( succeed ) return task_result(); //Simulate successful result. else return leaf::error( failed_thread_id{std::this_thread::get_id()}, failure_info1{"info"}, failure_info2{42}, failure_info4{42} ); } //Launch the specified number of asynchronous tasks. In case an asynchronous task fails, its error info //(of the type list used to instantiate leaf::capture) is captured in a leaf::captured_result, which //transports it to the main thread. template std::vector>> launch_async_tasks( int thread_count ) { std::vector>> fut; std::generate_n( std::inserter(fut,fut.end()), thread_count, [ ] { return std::async( std::launch::async, leaf::capture_result( [ ] //leaf::capture returns leaf::captured_result... { return task(rand()%4); //...from the leaf::result returned by the task. } ) ); } ); return fut; } int main() { //Launch tasks, transport the specified types of error info. For demonstration, note that the task provides //failure_info4 which we don't care about, and that we say we could use failure_info3, but which the //task doesn't provide. So, we'll only get failed_thread_id, failure_info1 and failure_info2. auto fut = launch_async_tasks(42); //Collect results or deal with failures. for( auto & f : fut ) { f.wait(); //Storage for error info. leaf::expect exp; //Unpack the leaf::captured_result to get a leaf::result and, //in case of error, set its captured error info. if( leaf::result r = unpack(f.get()) ) { //Success! Use *r to access task_result. std::cout << "Success!" << std::endl; } else { //Failure! Handle error, print failure info. handle_error( exp, r, leaf::match( [ ] ( std::string const & v1, int v2, std::thread::id tid ) { std::cerr << "Error in thread " << tid << "! failure_info1: " << v1 << ", failure_info2: " << v2 << std::endl; } ) ); } } }