I am trying to write a general async_task(Executor& executor, Token&& token, Fn&& func, Args&&... args) async initiating function.
The goal is to wrap arbitrary, blocking, third-party functions in a thread, and provide an asio-based interface.
It's not perfect yet (for instance, I know I need to post the completion handlers on the executor instead of running them in the thread), but I feel quite close.
I have three issues and questions:
Why does the program stop before all completion handlers have run? I shouldn't need a work guard, since the async operation is ongoing, right? EDIT: I'm mistaken. The non-callback handlers aren't being called at all, as evidenced by putting a sleep_for(1s) after the run() call. So my question is instead, why not?
Is this code violating some asio principle? It seems like something that would be fairly common to want to do, but I find very few examples of people doing similar things.
(bonus) I want to swap std::thread with concurrency::task<void>. The problem is then that I can't use a move-only type in the lambda capture. I tried self = make_shared<remove_reference_t<Self>>(move(self)), but this caused the three handlers to just print str: without the args. I believe this has something to do with the fact that the Self type (really a asio::detail::compose_op) contains a moved-in copy of the impl. So when I go to print, I'm using the old moved-from version. Anyone have any insight why that might be the case?
#include <chrono>
#include <iostream>
#include <memory>
#include <thread>
#include "asio.hpp"
template <typename Fn, typename... Args>
struct async_task_impl {
std::decay_t<Fn> fn_;
std::tuple<std::decay_t<Args>...> args_;
async_task_impl(Fn&& fn, Args&&... args)
: fn_(std::forward<Fn>(fn)), args_(std::forward<Args>(args)...) {}
template <typename Self>
auto operator()(Self& self) {
// #todo: use concurrency::create_task
auto t =
std::thread([me = *this, // copy impl into thread
self = std::move(self) // move composed_op into thread?
]() mutable {
try {
std::apply(me.fn_, me.args_);
self.complete({});
} catch (std::exception& e) {
self.complete(std::current_exception());
}
});
t.detach();
}
};
// runs some blocking task on its own thread and wraps it in asio
template <typename Executor, typename Token, typename Fn, typename... Args>
auto async_task(Executor& executor, Token&& token, Fn&& func, Args&&... args) {
return asio::async_compose<Token, void(std::exception_ptr)>(
async_task_impl(std::forward<Fn>(func), std::forward<Args>(args)...),
token, executor);
}
Test code: Godbolt
void slow_print(std::string str) {
static std::mutex m;
std::this_thread::sleep_for(std::chrono::milliseconds(500));
{
std::unique_lock lk(m);
std::cout << "slow_print: " << str << "\n";
}
std::this_thread::sleep_for(std::chrono::milliseconds(500));
}
int main() {
try {
asio::io_context ctx;
using namespace std::string_literals;
async_task(
ctx, [](std::exception_ptr) { std::cout << "callback done\n"; },
slow_print, "callback"s);
asio::co_spawn(
ctx,
[&]() -> asio::awaitable<void> {
co_await async_task(ctx, asio::use_awaitable, slow_print, "coro"s);
},
asio::detached);
auto f = std::async(std::launch::async, [&] {
auto fut = async_task(ctx, asio::use_future, slow_print, "future"s);
fut.get();
});
ctx.run();
} catch (std::exception& e) {
std::cout << e.what() << "\n";
}
return 0;
}
SHORT ANSWERS
Why does the program stop before all completion handlers have run?
I have no direct idea, your own Godbolt link seems to the premise, and so does this slightly embellished example: https://godbolt.org/z/WMKa4sqaE
See below for some notes about the changes.
Is this code violating some asio principle?
Maybe. See below.
It seems like something that would be fairly common to want to do, but I find very few examples of people doing similar things.
Yes. The docs have a very similar example: "To see this in practice, let's use a detached thread to adapt a synchronous operation into an asynchronous one"
(bonus) I want to swap std::thread with concurrency::task. The problem is then that I can't use a move-only type in the lambda capture. I tried self = make_shared<remove_reference_t>(move(self)), but this caused the three handlers to just print str: without the args. I believe this has something to do with the fact that the Self type (really a asio::detail::compose_op) contains a moved-in copy of the impl. So when I go to print, I'm using the old moved-from version. Anyone have any insight why that might be the case?
Beast has some helpers in their code base (stable_operation_base or something,
from the top of my head). Also see this blog post by Richard
Hodges
which creates a shared_composed_op from a composed_op that afford reference
stability of the standard operation implementation.
LONG ANSWERS
Yes. Resumed coroutines are not work - it's only when they suspend they usually enqueue a an operation with a completion handler to resume.
This is already the case with non-c++20 stackful coros, as Tanner has made very explicitly clear on occasion:
While spawn() adds work to the io_service (a handler that will start and jump to the coroutine), the coroutine itself is not work. To prevent the io_service event loop from ending while a coroutine is outstanding, it may be necessary to add work to the io_service before yielding.
What's worse: when you interact with more than one IO object they may be associated with different execution context, so you might need to track work on multiple executors.
The good news is that Asio (Chris) knew about this, which is why the signature of async_compose takes a list of IoObjectsOrExecutors:
template<
typename CompletionToken,
typename Signature,
typename Implementation,
typename... IoObjectsOrExecutors>
DEDUCED async_compose(
Implementation && implementation,
CompletionToken & token,
IoObjectsOrExecutors &&... io_objects_or_executors);
io_objects_or_executors
Zero or more I/O objects or I/O executors for which outstanding work must be maintained.
The composed operation specialized on your callable type will effective use boost::asio::prefer(ex, execution::outstanding_work.tracked) on all of the associated executors.
So as long as the composed operation (self) stays around, there should be work.
Services Are Not IO Objects Or Executors
You pass the service ("execution context") itself instead of an executor. When passing executors, prefer to pass by value.
Then What Went Wrong?
Again, I don't really know as I didn't exactly reproduce your complaints.
However, keep in mind the semantics of completion. In simplified pseudo-code, complete() does:
void complete() {
work_.reset();
handler_();
}
In other words, don't expect the work guards to stick past completion. In fact the order is pretty central to the allocation guarantees of the library.
(More) Reliable Debug Output
In C++ use std::flush (or std::endl) if you want output to appear.
Otherwise you might just be confused about output timing. This is frequently a
source of confusion when printing stuff from completion handlers in Asio.
For maximum insight, I'll introduce a variadic trace function that also timestamps each trace:
namespace {
using std::this_thread::sleep_for;
static auto now = std::chrono::steady_clock::now;
static auto start = now();
static std::mutex trace_mx;
static void trace(auto const&... args) {
std::unique_lock lk(trace_mx);
((std::cout << "at" << std::setw(5) << (now() - start) / 1ms << "ms ") << ... << args) << std::endl;
}
} // namespace
Side Note use_future
I don't get what you tried to achieve with the std::async version. As it stands you're demonstrating why std::async has been a bad design.
If you are looking to demonstrate Asio's future support, I'd write:
auto fut = async_task(ctx, asio::use_future, slow_print, "future"s);
try {
fut.get();
std::cout << "future done" << std::endl;
} catch (std::exception const& e) {
std::cout << "future error: " << e.what() << std::endl;
}
Now, to avoid interfering with the service because the future will block, I'd suggest running the service in the background instead:
asio::thread_pool ctx{1};
Of course, you can invert the situation by introducing a thread for the blocking wait:
std::thread ft{[ex] {
auto fut = async_task(ex, asio::use_future, slow_print, "future");
try {
fut.get();
std::cout << "future done" << std::endl;
} catch (std::exception const& e) {
std::cout << "future error: " << e.what() << std::endl;
}
}};
ctx.run();
ft.join();
Double Moves
In your task implementation, you both move self and copy *this. However
compose_op aggregates your async_task_impl (as the impl_ member), so
there is a timing link between those. As far as I know the evaluation order or
lambda captures in unspecified.
I'd suggest avoiding the unnecessary copy:
std::thread([self = std::move(self)]() mutable {
auto& me = self.impl_;
try {
std::apply(me.fn_, me.args_);
self.complete({});
} catch (std::exception& e) {
self.complete(std::current_exception());
}
}).detach();
Or indeed, going for syntactic sugar:
std::thread([self = std::move(self)]() mutable {
auto& [fn, args] = self.impl_;
try {
std::apply(fn, args);
self.complete({});
} catch (std::exception& e) {
self.complete(std::current_exception());
}
}).detach();
To make it even more elegant, just pass the self as a mutable argument
instead of capturing it (this may not work with concurrency::create_task of
course):
std::thread([](auto self) {
auto& [fn, args] = self.impl_;
try {
std::apply(fn, args);
self.complete({});
} catch (std::exception& e) {
self.complete(std::current_exception());
}
}, std::move(self)).detach();
Perfect Storage vs. Perfect Forwarding
Another place where you are not 100% clear about the forwarding intent is in the async_task_impl constructor. Args... is already in non-deduced context there, so Args&&... mandates rvalues. This might be why you used ""s-literals?
There are several ways to fix
Either you can let the compiler do its job:
async_task_impl(Fn&& fn, Args... args)
: fn_(std::forward<Fn>(fn))
, args_(std::move(args)...) {}
If you feel that's a pessimization (does your code-base use expensive non-move-aware argument types?), the simplest is to make the construct an independent template:
template <typename Fn2, typename... Args2>
async_task_impl(Fn2&& fn, Args2&&... args)
: fn_(std::forward<Fn2>(fn))
, args_(std::forward<Args2>(args)...) {}
I would probably go all-the-way and be explicit about the decay moment
using a deduction guide. The best part is you no longer require a
constructor at all:
template <typename Fn, typename... Args> struct async_task_impl {
Fn fn_;
std::tuple<Args...> args_;
auto operator()(auto& self) const {
// #todo: use concurrency::create_task
std::thread(
[](auto self) {
auto& [fn, args] = self.impl_;
try {
std::apply(fn, args);
self.complete({});
} catch (std::exception& e) {
self.complete(std::current_exception());
}
}, std::move(self)).detach();
}
};
template <typename... Init> async_task_impl(Init&&...) -> async_task_impl<std::decay_t<Init>...>;
// runs some blocking task on the windows thread pool and wraps it in a nice
// asio wrapper
template <typename Executor, typename Token, typename Fn, typename... Args>
auto async_task(Executor& executor, Token&& token, Fn&& func, Args&&... args) {
return asio::async_compose<Token, void(std::exception_ptr)>(
async_task_impl{std::forward<Fn>(func), std::forward<Args>(args)...}, token, executor);
}
Full Demo
Combining all the above:
Live On Coliru
Live On Compiler Explorer
#include "boost/asio.hpp"
#include <iomanip>
#include <iostream>
using namespace std::chrono_literals;
namespace {
using std::this_thread::sleep_for;
static auto now = std::chrono::steady_clock::now;
static auto start = now();
static std::mutex trace_mx;
static void trace(auto const&... args) {
std::unique_lock lk(trace_mx);
((std::cout << "at" << std::setw(5) << (now() - start) / 1ms << "ms ") << ... << args) << std::endl;
}
} // namespace
template <typename Fn, typename... Args> struct async_task_impl {
Fn fn_;
std::tuple<Args...> args_;
auto operator()(auto& self) const {
// #todo: use concurrency::create_task
std::thread(
[](auto self) {
auto& [fn, args] = self.impl_;
try {
std::apply(fn, args);
self.complete({});
} catch (std::exception& e) {
self.complete(std::current_exception());
}
},
std::move(self))
.detach();
}
};
template <typename... Init> async_task_impl(Init&&...) -> async_task_impl<std::decay_t<Init>...>;
// wrap blocking task in an asio wrapper
namespace asio = boost::asio;
template <typename Executor, typename Token, typename Fn, typename... Args>
auto async_task(Executor executor, Token&& token, Fn&& func, Args&&... args) {
return asio::async_compose<Token, void(std::exception_ptr)>(
async_task_impl{std::forward<Fn>(func), std::forward<Args>(args)...}, token, executor);
}
void slow_print(std::string str) {
sleep_for(500ms);
trace("slow_print: ", str);
sleep_for(500ms);
}
asio::awaitable<void> my_coro() {
auto ex = co_await asio::this_coro::executor;
co_await async_task(ex, asio::use_awaitable, slow_print, "coro");
trace("coro done");
}
void run_tests(auto ex) {
async_task(
ex, [](std::exception_ptr) { trace("callback done"); }, slow_print, "callback");
asio::co_spawn(ex, my_coro(), asio::detached);
std::thread ft{[ex] {
auto fut = async_task(ex, asio::use_future, slow_print, "future");
fut.get();
trace("future done");
}};
ft.join();
}
int main() try {
{
trace("Starting ctx1");
asio::io_context ctx1;
run_tests(ctx1.get_executor());
trace("Waiting ctx1");
ctx1.run();
trace("Done ctx1");
}
trace("----\n");
{
trace("Starting ctx2");
asio::thread_pool ctx2{1};
run_tests(ctx2.get_executor());
trace("Waiting ctx2");
ctx2.join();
trace("Done ctx2");
}
sleep_for(2s);
trace("Bye");
} catch (std::exception const& e) {
trace(e.what());
}
Prints
at 0ms Starting ctx1
at 500ms slow_print: callback
at 500ms slow_print: future
at 1000ms callback done
at 1000ms future done
at 1000ms Waiting ctx1
at 1501ms slow_print: coro
at 2001ms coro done
at 2001ms Done ctx1
at 2001ms ----
at 2001ms Starting ctx2
at 2501ms slow_print: callback
at 2501ms slow_print: future
at 2502ms slow_print: coro
at 3001ms callback done
at 3002ms future done
at 3002ms coro done
at 3002ms Waiting ctx2
at 3002ms Done ctx2
at 5002ms Bye
Related
I have got function f;
I want to throw exception 1s after start f.
I can't modify f(). It it possible to do it in c++?
try {
f();
}
catch (TimeoutException& e) {
//timeout
}
You can create a separate thread to run the call itself, and wait on a condition variable back in your main thread which will be signalled by the thread doing the call to f once it returns. The trick is to wait on the condition variable with your 1s timeout, so that if the call takes longer than the timeout you will still wake up, know about it, and be able to throw the exception - all in the main thread. Here is the code (live demo here):
#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std::chrono_literals;
int f()
{
std::this_thread::sleep_for(10s); //change value here to less than 1 second to see Success
return 1;
}
int f_wrapper()
{
std::mutex m;
std::condition_variable cv;
int retValue;
std::thread t([&cv, &retValue]()
{
retValue = f();
cv.notify_one();
});
t.detach();
{
std::unique_lock<std::mutex> l(m);
if(cv.wait_for(l, 1s) == std::cv_status::timeout)
throw std::runtime_error("Timeout");
}
return retValue;
}
int main()
{
bool timedout = false;
try {
f_wrapper();
}
catch(std::runtime_error& e) {
std::cout << e.what() << std::endl;
timedout = true;
}
if(!timedout)
std::cout << "Success" << std::endl;
return 0;
}
You can also use std::packaged_task to run your function f() in another thread. This solution is more or less similar to this one, only that it uses standard classes to wrap things up.
std::packaged_task<void()> task(f);
auto future = task.get_future();
std::thread thr(std::move(task));
if (future.wait_for(1s) != std::future_status::timeout)
{
thr.join();
future.get(); // this will propagate exception from f() if any
}
else
{
thr.detach(); // we leave the thread still running
throw std::runtime_error("Timeout");
}
You can probably even try to wrap it into a function template, to allow calling arbitrary functions with timeout. Something along the lines of:
template <typename TF, typename TDuration, class... TArgs>
std::result_of_t<TF&&(TArgs&&...)> run_with_timeout(TF&& f, TDuration timeout, TArgs&&... args)
{
using R = std::result_of_t<TF&&(TArgs&&...)>;
std::packaged_task<R(TArgs...)> task(f);
auto future = task.get_future();
std::thread thr(std::move(task), std::forward<TArgs>(args)...);
if (future.wait_for(timeout) != std::future_status::timeout)
{
thr.join();
return future.get(); // this will propagate exception from f() if any
}
else
{
thr.detach(); // we leave the thread still running
throw std::runtime_error("Timeout");
}
}
And then use:
void f1() { ... }
call_with_timeout(f1, 5s);
void f2(int) { ... }
call_with_timeout(f2, 5s, 42);
int f3() { ... }
int result = call_with_timeout(f3, 5s);
This is an online example: http://cpp.sh/7jthw
You can create a new thread and asynchronously wait for 1s to pass, and then throw an exception. However, exceptions can only be caught in the same thread where they're thrown, so, you cannot catch in the same thread where you called f(), like in your example code - but that's not a stated requirement, so it may be OK for you.
Only if f is guaranteed to return in less than 1s, can you do this synchronously:
store current time
call f()
wait for current time - stored time + 1s
But it may be quite difficult to prove that f in fact does return in time.
This builds on Smeehee's example, if you need one that takes variable number of arguments (see also https://github.com/goblinhack/c-plus-plus-examples/blob/master/std_thread_timeout_template/README.md)
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
int my_function_that_might_block(int x)
{
std::this_thread::sleep_for(std::chrono::seconds(10));
return 1;
}
template<typename ret, typename T, typename... Rest>
using fn = std::function<ret(T, Rest...)>;
template<typename ret, typename T, typename... Rest>
ret wrap_my_slow_function(fn<ret, T, Rest...> f, T t, Rest... rest)
{
std::mutex my_mutex;
std::condition_variable my_condition_var;
ret result = 0;
std::unique_lock<std::mutex> my_lock(my_mutex);
//
// Spawn a thread to call my_function_that_might_block().
// Pass in the condition variables and result by reference.
//
std::thread my_thread([&]()
{
result = f(t, rest...);
// Unblocks one of the threads currently waiting for this condition.
my_condition_var.notify_one();
});
//
// Detaches the thread represented by the object from the calling
// thread, allowing them to execute independently from each other. B
//
my_thread.detach();
if (my_condition_var.wait_for(my_lock, std::chrono::seconds(1)) ==
std::cv_status::timeout) {
//
// Throw an exception so the caller knows we failed
//
throw std::runtime_error("Timeout");
}
return result;
}
int main()
{
// Run a function that might block
try {
auto f1 = fn<int,int>(my_function_that_might_block);
wrap_my_slow_function(f1, 42);
//
// Success, no timeout
//
} catch (std::runtime_error& e) {
//
// Do whatever you need here upon timeout failure
//
return 1;
}
return 0;
}
If there's a generic method taking some handler:
template< typename HandlerType >
void Register( HandlerType && handler )
{
m_handler( std::forward< HandlerType >( handler ) );
}
and that handler is going to be invoked through an io_service at some point in the future:
void SomeEvent( )
{
// compute someParameter
m_IOService.post( std::bind( m_handler , someParameter ) );
}
How can it be detected if the caller of Register() had passed something wrapped by a strand, as in:
m_strand( m_IOService );
// ...
Register( m_strand.wrap( []( /*something*/ ){ /*...*/ } ) );
And how SomeEvent() should be changed in order to post the handler through the strand in such cases?
EDIT
When I asked this I didn't had the trouble of carefully reading io_service::strand::wrap docs, more specifically where it says that:
(...) Given a function object with the signature:
R f(A1 a1, ... An an);
If this function object is passed to the wrap function like so:
strand.wrap(f);
then the return value is a function object with the signature
void g(A1 a1, ... An an);
that, when invoked, executes code equivalent to:
strand.dispatch(boost::bind(f, a1, ... an));
And all I need is this indeed - I can just declare m_handler as an appropriate std::function<> and simply post it through the io_service in SomeEvent().
I realized this after reading the answer from #Arunmu, thus I'm accepting it. Nevertheless #Richard Hodges' answer has some good points on ASIO's executors logic and how it was improved in the standalone version.
If I understood your requirement clearly, you do not have to do anything out of the way if implemented like below (Read the comments in the code for explanation):
#include <iostream>
#include <type_traits>
#include <thread>
#include <memory>
#include <asio.hpp>
template <typename Handler>
class GenHandler
{
public:
GenHandler(Handler&& h): hndler_(std::forward<Handler>(h))
{}
template <typename... Args>
void operator()(Args&&... args)
{
std::cout << "GenHandler called" << std::endl;
hndler_();
}
private:
Handler hndler_;
};
template<typename HandlerType>
GenHandler<std::decay_t<HandlerType>> create_handler(HandlerType&& h)
{
return {std::forward<HandlerType>(h)};
}
template <typename Handler>
void SomeEvent(asio::io_service& ios, Handler& h)
{
ios.post([=] ()mutable { h(); });
}
int main() {
asio::io_service ios;
asio::io_service::strand strand{ios};
auto work = std::make_unique<asio::io_service::work>(ios);
std::thread t([&]() { ios.run(); });
// This creates a regular handler which when called by the
// io_context would first execute GenHandler::operator()
// and inside of which it would call the lambda passed below.
auto hndl = create_handler([] {
std::cout << "Regular Handle" << std::endl;
});
SomeEvent(ios, hndl);
///-------- Example 2 ---------////
// This creates a handler just like above, but instead wraps a
// strand handler i.e when GenHandler::operator() gets called
// it will execute the lambda passed to the wrap in the execution context
// of the strand.
auto hndl2 = create_handler(
strand.wrap([] {
std::cout << "Strand handler-depth 2" << std::endl;
}));
// This is a regular strand wrap which is passed to the
// io_service execution context. The lambda passed in the strand::wrap
// would be excuted the execution context of the strand.
auto str_handler = strand.wrap([=]() mutable {
std::cout <<"strand\n";
hndl2();
});
SomeEvent(ios, str_handler);
work.reset();
t.join();
return 0;
}
In the second example the handlers are called in the order as given below:
io_service is passed the strand::wrapped_handler. Therefore, the handler held by the wrapped_handler is executed inside the strand.
hndl2 which is GenHandler holding another strand::wrapped_handler is also called inside of the strand.
When GenHandler::operator() is called, it executes the held strand::wrapped_handler as well. This is done by dispatching the internal handler held by strand::wrapped_handler to the strand.
NOTE: For reasons quite unclear to me strand::wrap is deprecated. Author wants people to use bind_executor instead.
For boost asio the answer I think is in this template function:
namespace boost_asio_handler_cont_helpers {
template <typename Context>
inline bool is_continuation(Context& context)
{
#if !defined(BOOST_ASIO_HAS_HANDLER_HOOKS)
return false;
#else
using boost::asio::asio_handler_is_continuation;
return asio_handler_is_continuation(
boost::asio::detail::addressof(context));
#endif
}
} // namespace boost_asio_handler_cont_helpers
Which if I read it correctly is used to detect whether there is a "context" (i.e. a strand or io_service) in which the handler is to be executed.
The code in the reactor service then switches based on the result, either executing within the already existing context or not.
In standalone asio things have changed somewhat.
There is now a function to detect the context of a handler (if any). I wrote this code after consulting the author.
the relevant lines are:
auto ex = asio::get_associated_executor(handler, this->get_io_service().get_executor());
and..
asio::dispatch(ex, [handler = std::move(handler), future = std::move(future)]() mutable
{
// call the user-supplied handler
});
This is production code from "long running task" execution service:
template<class Task, class Handler>
void async_execute(implementation& impl, Task&& task, Handler&& handler)
{
VALUE_DEBUG_TRACE(module) << method(__func__, this);
using task_type = std::decay_t<Task>;
static_assert(is_callable_t<task_type, long_running_task_context>(), "");
using result_type = std::result_of_t<task_type(long_running_task_context)>;
using promise_type = std::promise<result_type>;
using future_type = std::future<result_type>;
using handler_type = std::decay_t<Handler>;
static_assert(is_callable_t<handler_type, future_type>(), "");
using handler_result_type = std::result_of<handler_type(future_type)>;
auto ex = asio::get_associated_executor(handler, this->get_io_service().get_executor());
if (not impl)
{
post(ex, [handler = std::forward<Handler>(handler)]() mutable
{
promise_type promise;
promise.set_exception(std::make_exception_ptr(system_error(errors::null_handle)));
handler(promise.get_future());
});
return;
}
auto handler_work = make_work(ex);
auto& ios = get_io_service();
auto impl_ptr = impl.get();
auto async_handler = [this,
&ios,
impl_ptr,
handler_work, ex,
handler = std::forward<Handler>(handler)]
(detail::long_running_task_op::identifier ident,
auto future) mutable
{
assert(impl_ptr);
VALUE_DEBUG_TRACE(module) << method("async_execute::async_handler", this, ident);
asio::dispatch(ex, [handler = std::move(handler), future = std::move(future)]() mutable
{
VALUE_DEBUG_TRACE(module) << method("async_execute::completion_handler");
handler(std::move(future));
});
assert(impl_ptr);
impl_ptr->remove_op(ident);
};
using async_handler_type = decltype(async_handler);
static_assert(is_callable_t<async_handler_type, detail::long_running_task_op::identifier, future_type>(), "");
auto op = detail::long_running_task_op(std::forward<Task>(task), std::move(async_handler));
auto ident = op.get_identifier();
impl->add_op(ident);
auto lock = lock_type(this->_queue_mutex);
_ops.emplace(ident, op);
lock.unlock();
this->post_execute();
}
I have got function f;
I want to throw exception 1s after start f.
I can't modify f(). It it possible to do it in c++?
try {
f();
}
catch (TimeoutException& e) {
//timeout
}
You can create a separate thread to run the call itself, and wait on a condition variable back in your main thread which will be signalled by the thread doing the call to f once it returns. The trick is to wait on the condition variable with your 1s timeout, so that if the call takes longer than the timeout you will still wake up, know about it, and be able to throw the exception - all in the main thread. Here is the code (live demo here):
#include <iostream>
#include <chrono>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std::chrono_literals;
int f()
{
std::this_thread::sleep_for(10s); //change value here to less than 1 second to see Success
return 1;
}
int f_wrapper()
{
std::mutex m;
std::condition_variable cv;
int retValue;
std::thread t([&cv, &retValue]()
{
retValue = f();
cv.notify_one();
});
t.detach();
{
std::unique_lock<std::mutex> l(m);
if(cv.wait_for(l, 1s) == std::cv_status::timeout)
throw std::runtime_error("Timeout");
}
return retValue;
}
int main()
{
bool timedout = false;
try {
f_wrapper();
}
catch(std::runtime_error& e) {
std::cout << e.what() << std::endl;
timedout = true;
}
if(!timedout)
std::cout << "Success" << std::endl;
return 0;
}
You can also use std::packaged_task to run your function f() in another thread. This solution is more or less similar to this one, only that it uses standard classes to wrap things up.
std::packaged_task<void()> task(f);
auto future = task.get_future();
std::thread thr(std::move(task));
if (future.wait_for(1s) != std::future_status::timeout)
{
thr.join();
future.get(); // this will propagate exception from f() if any
}
else
{
thr.detach(); // we leave the thread still running
throw std::runtime_error("Timeout");
}
You can probably even try to wrap it into a function template, to allow calling arbitrary functions with timeout. Something along the lines of:
template <typename TF, typename TDuration, class... TArgs>
std::result_of_t<TF&&(TArgs&&...)> run_with_timeout(TF&& f, TDuration timeout, TArgs&&... args)
{
using R = std::result_of_t<TF&&(TArgs&&...)>;
std::packaged_task<R(TArgs...)> task(f);
auto future = task.get_future();
std::thread thr(std::move(task), std::forward<TArgs>(args)...);
if (future.wait_for(timeout) != std::future_status::timeout)
{
thr.join();
return future.get(); // this will propagate exception from f() if any
}
else
{
thr.detach(); // we leave the thread still running
throw std::runtime_error("Timeout");
}
}
And then use:
void f1() { ... }
call_with_timeout(f1, 5s);
void f2(int) { ... }
call_with_timeout(f2, 5s, 42);
int f3() { ... }
int result = call_with_timeout(f3, 5s);
This is an online example: http://cpp.sh/7jthw
You can create a new thread and asynchronously wait for 1s to pass, and then throw an exception. However, exceptions can only be caught in the same thread where they're thrown, so, you cannot catch in the same thread where you called f(), like in your example code - but that's not a stated requirement, so it may be OK for you.
Only if f is guaranteed to return in less than 1s, can you do this synchronously:
store current time
call f()
wait for current time - stored time + 1s
But it may be quite difficult to prove that f in fact does return in time.
This builds on Smeehee's example, if you need one that takes variable number of arguments (see also https://github.com/goblinhack/c-plus-plus-examples/blob/master/std_thread_timeout_template/README.md)
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
int my_function_that_might_block(int x)
{
std::this_thread::sleep_for(std::chrono::seconds(10));
return 1;
}
template<typename ret, typename T, typename... Rest>
using fn = std::function<ret(T, Rest...)>;
template<typename ret, typename T, typename... Rest>
ret wrap_my_slow_function(fn<ret, T, Rest...> f, T t, Rest... rest)
{
std::mutex my_mutex;
std::condition_variable my_condition_var;
ret result = 0;
std::unique_lock<std::mutex> my_lock(my_mutex);
//
// Spawn a thread to call my_function_that_might_block().
// Pass in the condition variables and result by reference.
//
std::thread my_thread([&]()
{
result = f(t, rest...);
// Unblocks one of the threads currently waiting for this condition.
my_condition_var.notify_one();
});
//
// Detaches the thread represented by the object from the calling
// thread, allowing them to execute independently from each other. B
//
my_thread.detach();
if (my_condition_var.wait_for(my_lock, std::chrono::seconds(1)) ==
std::cv_status::timeout) {
//
// Throw an exception so the caller knows we failed
//
throw std::runtime_error("Timeout");
}
return result;
}
int main()
{
// Run a function that might block
try {
auto f1 = fn<int,int>(my_function_that_might_block);
wrap_my_slow_function(f1, 42);
//
// Success, no timeout
//
} catch (std::runtime_error& e) {
//
// Do whatever you need here upon timeout failure
//
return 1;
}
return 0;
}
I am implementing a concurrent wrapper as introduced by Herb Sutter presented in his talk "C++ and Beyond 2012".
template <typename T>
class ConcurrentWrapper {
private:
std::deque<std::unique_ptr<std::function<void()>>> _tasks;
std::mutex _mutex;
std::condition_variable _cond;
T _object;
std::thread _worker;
std::atomic<bool> _done {false};
public:
template <typename... ArgsT>
ConcurrentWrapper(ArgsT&&... args) :
_object {std::forward<ArgsT>(args)...},
_worker {
[&]() {
typename decltype(_tasks)::value_type task;
while(!_done) {
{
std::unique_lock<std::mutex> lock(_mutex);
while(_tasks.empty()) {
_cond.wait(lock);
}
task = std::move(_tasks.front());
_tasks.pop_front();
}
(*task)();
}
}
} {
}
~ConcurrentWrapper() {
{
std::unique_lock<std::mutex> lock(_mutex);
_tasks.push_back(std::make_unique<std::function<void()>>(
[&](){_done = true;}
));
}
_cond.notify_one();
_worker.join();
}
template <typename F, typename R = std::result_of_t<F(T&)>>
std::future<R> operator()(F&& f) {
std::packaged_task<R(T&)> task(std::forward<F>(f));
auto fu = task.get_future();
{
std::unique_lock<std::mutex> lock(_mutex);
_tasks.push_back(std::make_unique<std::function<void()>>(
[this, task=MoveOnCopy<decltype(task)>(std::move(task))]() {
task.object(this->_object);
}
));
}
_cond.notify_one();
return fu;
}
};
Basically, the idea is to wrap an object and provide thread-safe access in FIFO order using operation (). However, in some runs (not always happen), the following program hanged:
ConcurrentWrapper<std::vector<int>> results;
results(
[&](std::vector<T>& data) {
std::cout << "sorting...\n";
std::sort(data.begin(), data.end());
std::cout << "done ...\n";
EXPECT_EQ(data, golden);
}
).get();
However, the program work correctly without explicitly calling get() method.
results(
[&](std::vector<T>& data) {
std::cout << "sorting...\n";
std::sort(data.begin(), data.end());
std::cout << "done ...\n";
EXPECT_EQ(data, golden);
}
); // Function correctly without calling get
What could the be problem? Did I implement something wrong? I noticed a posted here saying that "a packaged_task needs to be invoked before you call f.get(), otherwise you program will freeze as the future will never become ready." Is this true? If yes, how can I get this problem solved?
I was compiling the code using -std=c++1z -pthread with G++ 6.1
High level
I want to call some functions with no return value in a async mode without waiting for them to finish. If I use std::async the future object doesn't destruct until the task is over, this make the call not sync in my case.
Example
void sendMail(const std::string& address, const std::string& message)
{
//sending the e-mail which takes some time...
}
myResonseType processRequest(args...)
{
//Do some processing and valuate the address and the message...
//Sending the e-mail async
auto f = std::async(std::launch::async, sendMail, address, message);
//returning the response ASAP to the client
return myResponseType;
} //<-- I'm stuck here until the async call finish to allow f to be destructed.
// gaining no benefit from the async call.
My questions are
Is there a way to overcome this limitation?
if (1) is no, should I implement once a thread that will take those "zombie" futures and wait on them?
Is (1) and (2) are no, is there any other option then just build my own thread pool?
note:
I rather not using the option of thread+detach (suggested by #galop1n) since creating a new thread have an overhead I wish to avoid. While using std::async (at least on MSVC) is using an inner thread pool.
Thanks.
You can move the future into a global object, so when the local future's destructor runs it doesn't have to wait for the asynchronous thread to complete.
std::vector<std::future<void>> pending_futures;
myResonseType processRequest(args...)
{
//Do some processing and valuate the address and the message...
//Sending the e-mail async
auto f = std::async(std::launch::async, sendMail, address, message);
// transfer the future's shared state to a longer-lived future
pending_futures.push_back(std::move(f));
//returning the response ASAP to the client
return myResponseType;
}
N.B. This is not safe if the asynchronous thread refers to any local variables in the processRequest function.
While using std::async (at least on MSVC) is using an inner thread pool.
That's actually non-conforming, the standard explicitly says tasks run with std::launch::async must run as if in a new thread, so any thread-local variables must not persist from one task to another. It doesn't usually matter though.
why do you not just start a thread and detach if you do not care on joining ?
std::thread{ sendMail, address, message}.detach();
std::async is bound to the lifetime of the std::future it returns and their is no alternative to that.
Putting the std::future in a waiting queue read by an other thread will require the same safety mechanism as a pool receiving new task, like mutex around the container.
Your best option, then, is a thread pool to consume tasks directly pushed in a thread safe queue. And it will not depends on a specific implementation.
Below a thread pool implementation taking any callable and arguments, the threads do poling on the queue, a better implementation should use condition variables (coliru) :
#include <iostream>
#include <queue>
#include <memory>
#include <thread>
#include <mutex>
#include <functional>
#include <string>
struct ThreadPool {
struct Task {
virtual void Run() const = 0;
virtual ~Task() {};
};
template < typename task_, typename... args_ >
struct RealTask : public Task {
RealTask( task_&& task, args_&&... args ) : fun_( std::bind( std::forward<task_>(task), std::forward<args_>(args)... ) ) {}
void Run() const override {
fun_();
}
private:
decltype( std::bind(std::declval<task_>(), std::declval<args_>()... ) ) fun_;
};
template < typename task_, typename... args_ >
void AddTask( task_&& task, args_&&... args ) {
auto lock = std::unique_lock<std::mutex>{mtx_};
using FinalTask = RealTask<task_, args_... >;
q_.push( std::unique_ptr<Task>( new FinalTask( std::forward<task_>(task), std::forward<args_>(args)... ) ) );
}
ThreadPool() {
for( auto & t : pool_ )
t = std::thread( [=] {
while ( true ) {
std::unique_ptr<Task> task;
{
auto lock = std::unique_lock<std::mutex>{mtx_};
if ( q_.empty() && stop_ )
break;
if ( q_.empty() )
continue;
task = std::move(q_.front());
q_.pop();
}
if (task)
task->Run();
}
} );
}
~ThreadPool() {
{
auto lock = std::unique_lock<std::mutex>{mtx_};
stop_ = true;
}
for( auto & t : pool_ )
t.join();
}
private:
std::queue<std::unique_ptr<Task>> q_;
std::thread pool_[8];
std::mutex mtx_;
volatile bool stop_ {};
};
void foo( int a, int b ) {
std::cout << a << "." << b;
}
void bar( std::string const & s) {
std::cout << s;
}
int main() {
ThreadPool pool;
for( int i{}; i!=42; ++i ) {
pool.AddTask( foo, 3, 14 );
pool.AddTask( bar, " - " );
}
}
Rather than moving the future into a global object (and manually manage deletion of unused futures), you can actually move it into the local scope of the asynchronously called function.
"Let the async function take its own future", so to speak.
I have come up with this template wrapper which works for me (tested on Windows):
#include <future>
template<class Function, class... Args>
void async_wrapper(Function&& f, Args&&... args, std::future<void>& future,
std::future<void>&& is_valid, std::promise<void>&& is_moved) {
is_valid.wait(); // Wait until the return value of std::async is written to "future"
auto our_future = std::move(future); // Move "future" to a local variable
is_moved.set_value(); // Only now we can leave void_async in the main thread
// This is also used by std::async so that member function pointers work transparently
auto functor = std::bind(f, std::forward<Args>(args)...);
functor();
}
template<class Function, class... Args> // This is what you call instead of std::async
void void_async(Function&& f, Args&&... args) {
std::future<void> future; // This is for std::async return value
// This is for our synchronization of moving "future" between threads
std::promise<void> valid;
std::promise<void> is_moved;
auto valid_future = valid.get_future();
auto moved_future = is_moved.get_future();
// Here we pass "future" as a reference, so that async_wrapper
// can later work with std::async's return value
future = std::async(
async_wrapper<Function, Args...>,
std::forward<Function>(f), std::forward<Args>(args)...,
std::ref(future), std::move(valid_future), std::move(is_moved)
);
valid.set_value(); // Unblock async_wrapper waiting for "future" to become valid
moved_future.wait(); // Wait for "future" to actually be moved
}
I am a little surprised it works because I thought that the moved future's destructor would block until we leave async_wrapper. It should wait for async_wrapper to return but it is waiting inside that very function. Logically, it should be a deadlock but it isn't.
I also tried to add a line at the end of async_wrapper to manually empty the future object:
our_future = std::future<void>();
This does not block either.
You need to make your future a pointer. Below is exactly what you are looking for:
std::make_unique<std::future<void>*>(new auto(std::async(std::launch::async, sendMail, address, message))).reset();
Live example
i have no idea what i'm doing, but this seem to work:
// :( http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3451.pdf
template<typename T>
void noget(T&& in)
{
static std::mutex vmut;
static std::vector<T> vec;
static std::thread getter;
static std::mutex single_getter;
if (single_getter.try_lock())
{
getter = std::thread([&]()->void
{
size_t size;
for(;;)
{
do
{
vmut.lock();
size=vec.size();
if(size>0)
{
T target=std::move(vec[size-1]);
vec.pop_back();
vmut.unlock();
// cerr << "getting!" << endl;
target.get();
}
else
{
vmut.unlock();
}
}while(size>0);
// ¯\_(ツ)_/¯
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
});
getter.detach();
}
vmut.lock();
vec.push_back(std::move(in));
vmut.unlock();
}
it creates a dedicated getter thread for each type of future you throw at it (eg. if you give a future and future, you'll have 2 threads. if you give it 100x future, you'll still only have 2 threads), and when there's a future you don't want to deal with, just do notget(fut); - you can also noget(std::async([]()->void{...})); works just fine, no block, it seems. warning, do not try to get the value from a future after using noget() on it. that's probably UB and asking for trouble.