emplace lambda task that used packaged_task into a queue - c++

So I have this enqueue implementation for a threadpool
template <typename F, typename... Args>
auto enqueue(F&& f, Args&&... args) -> std::future<decltype(f(args...))> {
using return_type = decltype(f(args...));
auto task = std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
auto result = task->get_future();
{
std::unique_lock<std::mutex> lock(m_queue_mutex);
if (m_stop)
throw std::runtime_error("enqueue on stopped ThreadPool");
m_tasks.emplace([task]() { (*task)(); });
}
m_condition.notify_one();
return result;
}
So far so good, but I would like to avoid using memory allocation and not use the make_shared.
So I change it to this:
template <typename F, typename... Args>
auto enqueue(F&& f, Args&&... args) -> std::future<decltype(f(args...))> {
using return_type = decltype(f(args...));
auto task = std::packaged_task<return_type()>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
auto result = task.get_future();
{
std::unique_lock<std::mutex> lock(m_queue_mutex);
if (m_stop)
throw std::runtime_error("enqueue on stopped ThreadPool");
m_tasks.emplace([task = std::move(task)]() mutable { task(); });
}
m_condition.notify_one();
return result;
}
As far as I know, there is no copy here.
the task should be moved into the lambda and the lambda should be moved into the queue but still, I get this error:
use of deleted function ‘std::packaged_task<_Res(_ArgTypes
...)>::packaged_task(const std::packaged_task<_Res(_ArgTypes ...)>&)
[with _Res = void; _ArgTypes = {}]’ 38 |
m_tasks.emplace(task mutable { task(); });
what I understand is that I'm trying to copy the packaged_task and its copy constructor is deleted.
here you can play with the full code
https://godbolt.org/z/bEsPfabz6
thanks!

Related

Type of lambda with parameter pack

Consider the following (https://godbolt.org/z/sfT3aesvK):
#include <utility>
#include <vector>
struct A { constexpr static int type = 0; };
template <typename Func, typename... Args>
int foo(Func func, Args&& ... args) {
auto call_with_A = [func](Args&& ... args) {
return func.template operator()<A>(std::forward<Args>(args)...);
};
std::vector<int(*)(Args&&...) /* what goes here? */> vec{{call_with_A}};
int acc = 0;
for (auto fn : vec) {
acc += fn(std::forward<Args>(args)...);
}
return acc;
}
int bar() {
return 1 + foo([]<typename T>(int a, int b) {
return T::type + a + b;
}, 2, 3);
}
The above does not compile, because
no known conversion from '(lambda at <source>:8:24)' to 'int (*)(int &&, int &&)' for 1st argument
My question is what the template type T so that std::vector<T> will accept call_with_A as an element?
I tried to print what decltype(call_with_A) is, but this seems to just be a (lambda at [...]) expression for the compiler.
The type of a lambda expression is "unutterable". It cannot be written down directly. However, you can declare a typedef alias for the type:
auto call_with_A = /* lambda */;
using LambdaType = decltype(call_with_A);
std::vector<LambdaType> vec = {call_with_A};
You can also use class template argument deduction if you don't need to mention the type anyway:
auto call_with_A = /* lambda */;
std::vector vec = {call_with_A};
// the type of `vec` is `std::vector<decltype(call_with_A)>`
Every lambda has a different type - even they have the same signature. Lambda functions that have identical body also have different type.
You can declare a vector of type using decltype. However, it is not useful. For example.
template <typename Func, typename... Args>
int foo(Func func, Args&& ... args) {
auto call_with_A = [func](Args&& ... args) {
return func.template operator()<A1>(std::forward<Args>(args)...);
};
auto call_with_A1 = [func](Args&& ... args) {
return func.template operator()<A1>(std::forward<Args>(args)...);
};
auto call_with_A2 = [func](Args&& ... args) {
return func.template operator()<A1>(std::forward<Args>(args)...);
};
std::vector<decltype(call_with_A)> vec;
vec.push_back(call_with_A);
vec.push_back(call_with_A1); // Not OK
vec.push_back(call_with_A2); // Not OK
return 0;
}
Your best option is to use std::vector of std::function. For example.
template <typename Func, typename... Args>
int foo(Func func, Args&& ... args) {
auto call_with_A = [func](Args&& ... args) {
return func.template operator()<A1>(std::forward<Args>(args)...);
};
auto call_with_A1 = [func](Args&& ... args) {
return func.template operator()<A1>(std::forward<Args>(args)...);
};
auto call_with_A2 = [func](Args&& ... args) {
return func.template operator()<A1>(std::forward<Args>(args)...);
};
std::vector<std::function<int(Args...)>> vec;
vec.push_back(call_with_A);
vec.push_back(call_with_A1);
vec.push_back(call_with_A2);
return 0;
}

How to run function after delay asynchronously in C++

I want to implement something like Java's TimerTask in C++. I want to use it for invoking functions sometimes, not periodic. For periodic launching it will be a good idea to implement "event loop" scheme with 2 threads, with creating tasks in the first thread and process it in the second. But I do not want to write much code. So I've written smth like this:
template <typename F, typename... Args>
auto timed_run(const uint64_t delay_ms, const F& function, Args... args) {
const auto f = [&] {
std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
function(args...);
};
auto future = std::async(std::launch::async, f);
return future;
}
But it does not work as I need because it is not asynchronous at all due to it waits at future destructor as described there.
So we need to create thread by ourselves. Okay, lets do it:
template <typename F, typename... Args>
auto timed_run(const uint64_t delay_ms, const F& function, Args... args) {
std::packaged_task<void()> task([&]() {
std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
function(args...);
});
auto future = task.get_future();
std::thread thread(std::move(task));
thread.detach();
return future;
}
In this implementation the are no locks and waits, but it simply does not run our function. It is because we can't use sleep on the detached threads.
So, how can I implement what i want?
You can have your timed_run function launch an async task and return a future. At the callee point, just wait for the async task to complete.
[Demo]
#include <chrono>
#include <cstdint> // uint64_t
#include <fmt/core.h>
#include <future> // async
#include <thread> // this_thread
template <typename F, typename... Args>
auto timed_run(const std::uint64_t delay_ms, F&& f, Args&&... args) {
return std::async(std::launch::async, [=](){
std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
f(args...);
});
}
int main() {
using namespace std::chrono_literals;
auto print_dots = []() {
for (int i{4}; i > 0; --i) {
fmt::print(".\n");
std::this_thread::sleep_for(10ms);
}
};
auto print_square = [](int n) { fmt::print("{}\n", n*n); };
auto f1{ timed_run(0, print_dots) };
auto f2{ timed_run(20, print_square, 2) };
f1.get();
f2.get();
}
// Outputs something like:
//
// ..4..
template <typename F, typename... Args>
auto timed_run(const uint64_t delay_ms, F&& function, Args&&... args) {
std::packaged_task<void()> task([=]() {
std::this_thread::sleep_for(std::chrono::milliseconds(delay_ms));
function(args...);
});
auto future = task.get_future();
std::thread(std::move(task)).detach();
return future;
}

Wrapper to std::async() not working

EDIT : The call to std::bind() can be replaced with something else, I just want runAsyncTerminateOnException() to work with the same signature than std::async(), like just a wrapper to it
I am trying to create a wrapper to std::async().
Do you know how to make the wrapper working as well when a direct call to std::async() works ?
Note : I will not modify the print() function signature, this is an example. I would like the wrapper to be generic and to work for every possible parameters that are well handled by a direct call to std::async().
Thank you.
http://ideone.com/HbBqeo
#include <iostream>
#include <functional>
#include <future>
template<class Fn, class... Args>
inline auto runAsyncTerminateOnException(Fn&& fn, Args&&... args) {
auto make_call = std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...);
return std::async(std::launch::async, [=]() -> decltype(make_call()) {
try {
return make_call();
} catch (...) {
std::cout << "Terminate Called!" << std::endl;
std::terminate();
}
});
}
struct Foo {
template<class... Args>
void print(Args&&... args) {
printf("Foo::print(%d)\n", std::forward<Args>(args)...);
}
};
int main() {
Foo foo;
std::future<void> future = std::async(std::launch::async, &Foo::print<int>, &foo, 2);
std::future<void> future2 = runAsyncTerminateOnException(&Foo::print<int>, &foo, 2);
// your code goes here
return 0;
}
You need to change your runAsyncTerminateOnException call as follows:
std::future<void> future2 =
runAsyncTerminateOnException(&Foo::print<const int&>, &foo, 2);
This is due to an unfortunate interaction between std::bind, variadic templates and perfect forwarding.
I suggest you to use lambdas instead, which are almost always superior to std::bind. (For more information, see this talk from STL.)
template<class Fn>
inline auto runAsyncTerminateOnException(Fn&& fn)
{
return std::async(std::launch::async, [=]() -> decltype(fn()) {
try {
return fn();
} catch (...) {
std::cout << "Terminate Called!" << std::endl;
std::terminate();
}
});
}
(Note that I'm copying fn into the lambda - if you want a more correct and generic solution, you should consider perfect-forward capturing the object into the lambda.)
std::future<void> future2 =
runAsyncTerminateOnException([&foo]{ return foo.print(2); });
wandbox example
I found the solution for c++17.
It works only if we do not use auto for the return type of runTerminateOnException().
template<class Fn, class... Args>
inline std::result_of_t<Fn&&(Args&&...)> runTerminateOnException(Fn&& fn, Args&&... args) {
try {
return std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...);
} catch (...) {
std::terminate();
}
}
template<class Fn, class... Args>
inline auto runAsyncTerminateOnException(Fn&& fn, Args&&... args) {
return std::async(std::launch::async, runTerminateOnException<Fn, Args&&...>, std::forward<Fn>(fn), std::forward<Args>(args)...);
}

Move all arguments to lambda

I want to create lambda that will accept any number of arguments like:
template <typename... Args>
void f(Args... args) {
auto l = [args...]() {
g(args...);
}
// use l
}
Problem here is that it doesn't work with move-only types. If it was only 1 arg I would do smth like
void f(Arg arg) {
auto l = [arg = std::move(arg)]() {
g(move(arg));
}
}
How to move all args to lambda?
template <class... Args>
void f(Args... args) {
auto l = [tup=std::make_tuple(std::move(args)...)] {
std::apply([](auto&&...args){
g(decltype(args)(args)...);
}, tup );
};
}
A bit icky.
Pack them into a tuple, then unpack tuple with std::apply. If you lack std::apply write yourself an equivalent one.
If you want to invoke g with rvalues, make outer lambda mutable, and move tuple into inner lambda.
Inner lambda can capture by default & if you want access to args of outer or the like.
We can even abstract this pattern a bit:
template<class F, class...Args>
auto forward_capture( F&& f, Args&&...args ) {
return [
f=std::forward<F>(f),
tup=std::make_tuple(std::forward<Args>(args)...)
]{
return std::apply( f, tup );
};
}
use:
template <typename... Args>
void f(Args... args) {
auto l = forward_capture(
[](auto&&...args) {
g(args...);
},
std::move(args)...
);
// use l
}
If you want the capture list first, we can do it:
template<class...Args>
auto forward_capture( Args&&...args ) {
return [
tup=std::make_tuple(std::forward<Args>(args)...)
](auto&& f)mutable{
return [
f=decltype(f)(f),
tup=std::move(tup)
]{
return std::apply( f, tup );
};
};
}
use:
template <typename... Args>
void f(Args... args) {
auto l = forward_capture(std::move(args)...)(
[](auto&&...args) {
g(args...);
}
);
// use l
}
which has the "advantage" that we have 3 nested lambdas.
Or more fun:
template<class...Args>
struct arrow_star {
std::tuple<Args...> args;
template<class F>
auto operator->*(F&& f)&& {
return [f=std::forward<F>(f),args=std::move(args)]()mutable{
return std::experimental::apply( std::move(f), std::move(args) );
};
}
};
template<class...Args>
arrow_star<std::decay_t<Args>...> forward_capture( Args&&...args ) {
return {std::make_tuple(std::forward<Args>(args)...)};
}
template<class...Args>
auto f(Args... args)
{
return
forward_capture( std::move(args)... )
->*
[](auto&&...args){
g(decltype(args)(args)...);
};
}
live example.

How can I store generic packaged_tasks in a container?

I'm trying to take a 'task' in the style of std::async and store it in a container. I'm having to jump through hoops to achieve it, but I think there must be a better way.
std::vector<std::function<void()>> mTasks;
template<class F, class... Args>
std::future<typename std::result_of<typename std::decay<F>::type(typename std::decay<Args>::type...)>::type>
push(F&& f, Args&&... args)
{
auto func = std::make_shared<std::packaged_task<typename std::result_of<typename std::decay<F>::type(typename std::decay<Args>::type...)>::type()>>(std::bind(std::forward<F>(f), std::forward<Args>(args)...));
auto future = func->get_future();
// for some reason I get a compilation error in clang if I get rid of the `=, ` in this capture:
mTasks.push_back([=, func = std::move(func)]{ (*func)(); });
return future;
}
So I'm using bind -> packaged_task -> shared_ptr -> lambda -> function. How can I do this better/more optimally? It would certainly be easier if there was a std::function which could take a non-copyable but moveable task. Can I std::forward args into the capture of a lambda, or do I have to use bind?
There is no kill like overkill.
Step 1: write a SFINAE friendly std::result_of and a function to help calling via tuple:
namespace details {
template<size_t...Is, class F, class... Args>
auto invoke_tuple( std::index_sequence<Is...>, F&& f, std::tuple<Args>&& args)
{
return std::forward<F>(f)( std::get<Is>(std::move(args)) );
}
// SFINAE friendly result_of:
template<class Invocation, class=void>
struct invoke_result {};
template<class T, class...Args>
struct invoke_result<T(Args...), decltype( void(std::declval<T>()(std::declval<Args>()...)) ) > {
using type = decltype( std::declval<T>()(std::declval<Args>()...) );
};
template<class Invocation, class=void>
struct can_invoke:std::false_type{};
template<class Invocation>
struct can_invoke<Invocation, decltype(void(std::declval<
typename invoke_result<Inocation>::type
>()))>:std::true_type{};
}
template<class F, class... Args>
auto invoke_tuple( F&& f, std::tuple<Args>&& args)
{
return details::invoke_tuple( std::index_sequence_for<Args...>{}, std::forward<F>(f), std::move(args) );
}
// SFINAE friendly result_of:
template<class Invocation>
struct invoke_result:details::invoke_result<Invocation>{};
template<class Invocation>
using invoke_result_t = typename invoke_result<Invocation>::type;
template<class Invocation>
struct can_invoke:details::can_invoke<Invocation>{};
We now have invoke_result_t<A(B,C)> which is a SFINAE friendly result_of_t<A(B,C)> and can_invoke<A(B,C)> which just does the check.
Next, write a move_only_function, a move-only version of std::function:
namespace details {
template<class Sig>
struct mof_internal;
template<class R, class...Args>
struct mof_internal {
virtual ~mof_internal() {};
// 4 overloads, because I'm insane:
virtual R invoke( Args&&... args ) const& = 0;
virtual R invoke( Args&&... args ) & = 0;
virtual R invoke( Args&&... args ) const&& = 0;
virtual R invoke( Args&&... args ) && = 0;
};
template<class F, class Sig>
struct mof_pimpl;
template<class R, class...Args, class F>
struct mof_pimpl<F, R(Args...)>:mof_internal<R(Args...)> {
F f;
virtual R invoke( Args&&... args ) const& override { return f( std::forward<Args>(args)... ); }
virtual R invoke( Args&&... args ) & override { return f( std::forward<Args>(args)... ); }
virtual R invoke( Args&&... args ) const&& override { return std::move(f)( std::forward<Args>(args)... ); }
virtual R invoke( Args&&... args ) && override { return std::move(f)( std::forward<Args>(args)... ); }
};
}
template<class R, class...Args>
struct move_only_function<R(Args)> {
move_only_function(move_only_function const&)=delete;
move_only_function(move_only_function &&)=default;
move_only_function(std::nullptr_t):move_only_function() {}
move_only_function() = default;
explicit operator bool() const { return pImpl; }
bool operator!() const { return !*this; }
R operator()(Args...args) & { return pImpl().invoke(std::forward<Args>(args)...); }
R operator()(Args...args)const& { return pImpl().invoke(std::forward<Args>(args)...); }
R operator()(Args...args) &&{ return std::move(*this).pImpl().invoke(std::forward<Args>(args)...); }
R operator()(Args...args)const&&{ return std::move(*this).pImpl().invoke(std::forward<Args>(args)...); }
template<class F,class=std::enable_if_t<can_invoke<decay_t<F>(Args...)>>
move_only_function(F&& f):
m_pImpl( std::make_unique<details::mof_pimpl<std::decay_t<F>, R(Args...)>>( std::forward<F>(f) ) )
{}
private:
using internal = details::mof_internal<R(Args...)>;
std::unique_ptr<internal> m_pImpl;
// rvalue helpers:
internal & pImpl() & { return *m_pImpl.get(); }
internal const& pImpl() const& { return *m_pImpl.get(); }
internal && pImpl() && { return std::move(*m_pImpl.get()); }
internal const&& pImpl() const&& { return std::move(*m_pImpl.get()); } // mostly useless
};
not tested, just spewed the code. The can_invoke gives the constructor basic SFINAE -- you can add "return type converts properly" and "void return type means we ignore the return" if you like.
Now we rework your code. First, your task are move-only functions, not functions:
std::vector<move_only_function<X>> mTasks;
Next, we store the R type calculation once, and use it again:
template<class F, class... Args, class R=std::result_of_t<std::decay<F>_&&(std::decay_t<Args>&&...)>>
std::future<R>
push(F&& f, Args&&... args)
{
auto tuple_args=std::make_tuple(std::forward<Args>(args)...)];
// lambda will only be called once:
std::packaged_task<R()> task([f=std::forward<F>(f),args=std::move(tuple_args)]
return invoke_tuple( std::move(f), std::move(args) );
});
auto future = func.get_future();
// for some reason I get a compilation error in clang if I get rid of the `=, ` in this capture:
mTasks.emplace_back( std::move(task) );
return future;
}
we stuff the arguments into a tuple, pass that tuple into a lambda, and invoke the tuple in a "only do this once" kind of way within the lambda. As we will only invoke the function once, we optimize the lambda for that case.
A packaged_task<R()> is compatible with a move_only_function<R()> unlike a std::function<R()>, so we can just move it into our vector. The std::future we get from it should work fine even though we got it before the move.
This should reduce your overhead by a bit. Of course, there is lots of boilerplate.
I have not compiled any of the above code, I just spewed it out, so the odds it all compiles are low. But the errors should mostly be tpyos.
Randomly, I decided to give move_only_function 4 different () overloads (rvalue/lvalue and const/not). I could have added volatile, but that seems reckless. Which increase boilerplate, admittedly.
Also my move_only_function lacks the "get at the underlying stored stuff" operation that std::function has. Feel free to type erase that if you like. And it treats (R(*)(Args...))0 as if it was a real function pointer (I return true when cast to bool, not like null: type erasure of convert-to-bool might be worthwhile for a more industrial quality implementation.
I rewrote std::function because std lacks a std::move_only_function, and the concept in general is a useful one (as evidenced by packaged_task). Your solution makes your callable movable by wrapping it with a std::shared_ptr.
If you don't like the above boilerplate, consider writing make_copyable(F&&), which takes an function object F and wraps it up using your shared_ptr technique to make it copyable. You can even add SFINAE to avoid doing it if it is already copyable (and call it ensure_copyable).
Then your original code would be cleaner, as you'd just make the packaged_task copyable, then store that.
template<class F>
auto make_function_copyable( F&& f ) {
auto sp = std::make_shared<std::decay_t<F>>(std::forward<F>(f));
return [sp](auto&&...args){return (*sp)(std::forward<decltype(args)>(args)...); }
}
template<class F, class... Args, class R=std::result_of_t<std::decay<F>_&&(std::decay_t<Args>&&...)>>
std::future<R>
push(F&& f, Args&&... args)
{
auto tuple_args=std::make_tuple(std::forward<Args>(args)...)];
// lambda will only be called once:
std::packaged_task<R()> task([f=std::forward<F>(f),args=std::move(tuple_args)]
return invoke_tuple( std::move(f), std::move(args) );
});
auto future = func.get_future();
// for some reason I get a compilation error in clang if I get rid of the `=, ` in this capture:
mTasks.emplace_back( make_function_copyable( std::move(task) ) );
return future;
}
this still requires the invoke_tuple boilerplate above, mainly because I dislike bind.