The question itself was the answer of another, but it aroused my curiosity about how to implement a fully functional, thread-safe task manager in a minimum number of lines of code.
I also wondered if it would be possible to wait for tasks as futures or perhaps provide a callback function.
Then, of course, this raised the question of whether these futures could use the .then(xxx) sexual extension syntax, and not block the code.
Here is my attempt.
A lot of fun for Christopher Kochhoff, author of boost::asio . Having studied his amazing work, I realized the importance of dividing classes into:
- handle - controls the lifetime of an object
- service - provides object logic, a state shared between object objects, and controls the lifetime of implementation objects if they survive the descriptor (usually everything that relies on a callback), and
- the implementation provides the state of each object.
So, here is a code call example:
int main() { task_manager mgr; // an example of using async callbacks to indicate completion and error mgr.submit([] { emit("task 1 is doing something"); std::this_thread::sleep_for(1s); emit("task 1 done"); }, [](auto err) { if (not err) { emit("task 1 completed"); } else { emit("task 1 failed"); } }); // an example of returning a future (see later) auto f = mgr.submit([] { emit("task 2 doing something"); std::this_thread::sleep_for(1500ms); emit("task 2 is going to throw"); throw std::runtime_error("here is an error"); }, use_future); // an example of returning a future and then immediately using its continuation. // note that the continuation happens on the task_manager thread pool mgr.submit([] { emit("task 3 doing something"); std::this_thread::sleep_for(500ms); emit("task 3 is done"); }, use_future) .then([](auto f) { try { f.get(); } catch(std::exception const& e) { emit("task 3 threw an exception: ", e.what()); } }); // block on the future of the second example try { f.get(); } catch (std::exception &e) { emit("task 2 threw: ", e.what()); } }
This will lead to the following conclusion:
task 1 is doing something task 2 doing something task 3 doing something task 3 is done task 1 done task 1 completed task 2 is going to throw task 2 threw: here is an error
And here is the full code (tested on apple clang, which is more messy than gcc, so if I skipped this-> to lambda, my apologies):
#define BOOST_THREAD_PROVIDES_FUTURE 1
source share