Thread pool in C++ not using references from args - c++

I am trying to get a thread pool to run a method were the arguments are passed by reference. The
method I want to run is:
void Foo(const std::vector<std::string> &arg1, std::vector<int> &arg2, int size) {//modify elements of arg2}
I am submitting this function to a thread pool:
Pool.submit(Foo, arg1,arg2,size);
...
template<typename F, typename... Args>
void submit(F&& f, Args&&... args) {
//Create a callable std::function with parameters that will be executed by a free std::thread
std::function<decltype(f(args...))()> func = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
//Place the callable std::function into a shared_ptr
auto pTask = std::make_shared<std::packaged_task<decltype(f(args...))()>> (func);
//Wrap packaged task into void std::function using a lambda std::function
std::function<void()> pWrappedTask = [pTask]() {(*pTask)();};
//Increment this for job status tracking
JobsRequested++;
//Enqueue generic wrapper std::function
JobQ.enqueue(pWrappedTask);
//Wake up one std::thread if its waiting
PoolCondVar.notify_one();
}
I found that the the arguments are not being passed by reference, so when the thread calls Foo, the original variable does not get modified. If I call the function without using the thread pool, the Foo works correctly. I think it has something to do with how I am setting up the function std::function<decltype(f(args...))()> func = std::bind(std::forward<F>(f), std::forward<Args>(args)...); because when I debug the function within each thread, the address of my arguments change between threads.
Thank you for any suggestions!

According to std::bind documentation:
The return type of std::bind holds a member object of type std::decay<F>::type constructed from std::forward<F>(f), and one object per each of args..., of type std::decay<Arg_i>::type, similarly constructed from std::forward<Arg_i>(arg_i).
Thanks to decay, the arguments are "stored-by-value", which means the arguments are either copy-constructed or move-constructed. This explains their different address.
As usually in such situations, the solution is in using std::reference_wrapper:
Pool.submit(Foo, std::ref(arg1), std::ref(arg2), size);
Live demo: https://godbolt.org/z/4M3vK1cr9

Related

Universal references in a thread function

I have been learning about perfect forwarding and the use of && in function templates (see this previous question of mine) and would like to know if my use of Args&& in StartDetachedThread() below is justified:
#include <thread>
class CObject {};
void MyThreadFunc(CObject&)
{
}
// ** Will not compile with this function declaration! **
void MyThreadFunc(CObject&&)
{
}
template<typename FunctionType, typename ...Args>
void StartDetachedThread(FunctionType func, Args&&... args)
{
thread([&]()
{
func(forward<Args>(args)...);
}).detach();
}
int main()
{
CObject object;
StartDetachedThread(MyThreadFunc, object);
CObject object2;
StartDetachedThread(MyThreadFunc, std::move(object2));
return 0;
}
This code simply creates a detached thread, running the supplied function passing to it the supplied arguments.
Hhowever, VS 2017 complains:
'StartDetachedThread': no matching overloaded function found
'void StartDetachedThread(FunctionType,Args &&...)': could not deduce template argument for 'FunctionType'
1) I know that arguments passed to the thread constructor are copied first, then passed by reference to the new thread, so is my attempt to have MyThreadFunc(CObject&&) called when I pass an rvalue reference never going to work?
2) Is there any value in having StartDetachedThread(FunctionType&& func, Args&&... args) - or is the && unnecessary for FunctionType?
3) Is there any value whatsoever in using Args&& when starting a thread like this, or should I always use Args?
The problem in your code has nothing to do with std::thread, it is because MyThreadFunc is ambiguous in this context:
// Which MyThreadFunc should be used?
StartDetachedThread(MyThreadFunc, object);
Regarding your question:
1) I know that arguments passed to the thread constructor are copied first, then passed by reference to the new thread, [...]
In your example, the only copy is the copy of the lambda. The arguments are not copied here, if you want the argument to be copied you should use something like this:
std::thread(std::move(func), std::forward<Args>(args)...).detach();
...where you forward the arguments to std::thread constructor.
This is safer. — Think about what happens if the function StartDetachedThread ends while the thread is still running?
If you use this, you need to explicitly tell the compiler you want to call the reference version for object1 by using std::ref:
CObject object;
StartDetachedThread<void (CObject&)>(MyThreadFunc, std::ref(object)); // std::ref
CObject object2;
StartDetachedThread<void (CObject&&)>(MyThreadFunc, std::move(object2));
2) Is there any value in having StartDetachedThread(FunctionType&& func, Args&&... args) - or is the && unnecessary for FunctionType?
3) Is there any value whatsoever in using Args&& when starting a thread like this, or should I always use Args?
Using forwarding references allows you to call StartDetachedThread without having to move everything. If you use the above way for constructing a std::thread, then copies will be made for func and args anyway.
The issue is that which overload of MyThreadFunc is desired is not deducible by the compiler. There are at least two ways to fix it:
Rename one of the function so that it is clearer which one you want.
Use explicit template parameters:
StartDetachedThread<void (CObject&)>(MyThreadFunc, object);
StartDetachedThread<void (CObject&&)>(MyThreadFunc, std::move(object2));

Object passed in function pointer to other thread - how is it handled?

Imagine such code, that creates lambda function and passes it to other thread to be executed (method schedule_task_in_thread expect Functor as only parameter). What exactly happens to object o? Is there a temporary copy created until the method is executed? The wait() ensures the call is blocking.
#define INVOKE_IN_MYTHREAD(method_name, ...) \
return schedule_task_in_thread( [&](){ return mythread->method_name(__VA_ARGS__); }).wait().
void do_something( MyObject o ){
INVOKE_IN_MYTHREAD( method, o );
}
The problem is, that the mythread->method() reports the object o to be slightly different than it was in do_something(). I tried to catch all {copy|default|move}{constructor|assignments} but I don't see them being called.
class MyObject{
uint32_t a;
std::string b;
CryptoPP::Integer c;
}
Fields a and b are passed properly, field c is set to Integer(0).
Any ideas?
Your lambda is reference capturing all the arguments to the method, and those references are only valid while the calling thread is in the body of do_something.
If you instead have the lambda capture by value, there will be a copy.
Safer than your macro would be something like
template <typename Method, typename ... Args>
void invoke_in_mythread(Method method, Args ... args)
{
schedule_task_in_thread( [=](){ return mythread->method(std::forward<Args...>(args)); }).wait();
}

Get a reference to the lambda's captured value

I am using a function (not mine, from a library I don't control) with a signature similar to this:
template<typename T, typename F>
void do_async(T const&, F); // the second parameter is a callable
and it usually used like this
do_async(obj, [this](){ ... });
I wrote a function similar to this that always uses the same callback lambda:
template<typename T>
void do_async_wrapper(T obj) {
do_async(obj, [this](){ ... });
}
My problems stem from the fact that since the obj is passed as a reference, it has to be kept alive until the callback is called. My function is supposed to take care of that so the caller doesn't have to worry about object lifetime. That is why it accepts by value.
I would like to do something like this in order to keep it alive:
template<typename T>
void do_async_wrapper(T obj) {
do_async(obj, [this, obj{std::move(obj)}](){ ... });
}
Obviously this wont (always) work as-is since the reference points to the function-local one which doesn't exist anymore, while the one kept alive is a (move-)copy of it.
Any suggestions?
As the functor is taken by value, you cannot store the object directly in the functor and pass a reference to it.
You may work-around that by using smart pointer as shared_ptr:
template<typename T>
void do_async_wrapper(T obj) {
auto ptr = std::make_shared<T>(std::move(obj));
do_async(*ptr, [this, ptr](){ /*...*/ });
}

return lambda by rvalue ref?

#include <iostream>
#include <functional>
template <typename... Args>
std::function<void(Args...)> pushToEventLoop(std::function<void(Args...)> && p_function)
{
auto func = [p_function](Args... args) ->void
{
// This is what i would do here, but requires too much source code
//ThreadPool::enque(std::bind(p_function, args...));
// This is what i'll do for the sake of the example.
p_function(args...);
};
return func;
}
int main()
{
auto function(pushToEventLoop(std::function<void(char const *)>(std::bind(std::printf, std::placeholders::_1))));
auto function2 = std::bind(function, "Hello World!\n");
function2();
return 0;
}
Is it possible and how, to return the "func" variable by rvalue ref?
I have a feeling that this is somehow totally insane, but I'd like to know why, so I can restore my sanity.
I have no idea if i have done something horribly wrong. Please provide feedback.
I built this thing so that I can make callbacks that are actually just posted to the treadpool for processing, without the caller or the target knowing anything about this. The middleman that binds them together makes the choice of how to connect them.
https://ideone.com/4Wfhb1
EDIT
Ok, so I thought that there is copying going on when I return the func variable. But apparently it's dealt with by RVO, so no copying takes place. I have not verified this, but now that I think about it, that would make sense.
If your question is how to return a lamba in the most eficient way, then just return it by value and use automatic return typ deduction:
//this will actually return a lmabda and not a std::function
template <typename... Args>
auto pushToEventLoop(std::function<void(Args...)> && p_function)
{
return [f = std::move(p_function)](Args... args)
{
f(args...);
};
}
This will leverage RVO and avoid any dynamic memory allocations that std::function might have to perform.
Also having an r-value reference parameter usually doesn't gain you anything, if you don't move from it (unless you require that specific interface for another reason). In order to do so here you can leverage c++14's generalized lambda capture (the compiler can't perform that optimization by itself, as p_function itself is an l-value).
Now, if your question on the other hand was, if/how you can return a (r- or l-value) reference to a non-static local variable from a function, then the answer is simply:
NEVER DO THAT!
I think what you're trying to do is to move p_function into your lambda while avoiding copies? Presumably this is for performance reasons?
In which case you probably want to write it like this:
template <typename... Args>
// return by value - because RVO will elide copies for us
std::function<void(Args...)>
// passing by r-value reference... ok no problem there
pushToEventLoop(std::function<void(Args...)> && p_function)
{
// but I want to MOVE my p_function into func
// this will require at least c++1y (c++14)
auto func = [p_function = std::move(p_function)](Args... args) ->void
{
// p_function has now been moved into the lambda ...
};
// ... p_function passed to us is now in a valid but undefined state
// so don't use it here
// allow RVO to do its thing
return func;
}

How C++11 threads are wrapped around pthreads

So C++11 threads are wrappers around pthreads on most systems, I am confused how the syntax for going from a variadic function to a more strict function with a specified return type might work (i.e. the callback function with pthreads) can someone give an example that could illustrate the same?
Suppose you have a C style interface that looks like:
Foo run( Foo(*)(void*), void* );
And you want to write:
template<class F, class...Args>
std::result_of<F(Args...)>
smart_run( F&& f, Args&&... args );
This is analogous to what you need to do to implement std::thread on top of pthreads. I simplified stuff a bit, because it is noise (no std ref support, no decaying, etc).
For the first step, take F and Args... and bind them up. Something like std::bind(f, args...) that returns a zero-arg function that returns the result.
With that, we just need to solve:
template<class F>
std::result_of<F()>
smart_run( F&& f );
which takes an arbitrary callable, then uses run above to run it.
The trick is to create a copy of f on the free store and a function that calls it like this:
template<class F>
std::result_of<F()>
smart_run( F&& f ){
struct data{
F f;
std::result_of_t<F()> r;
};
data*p = new data{std::forward<F>(f)};
Foo ignored=run(
[](void* p){
data* self=static_cast<data*>(p);
auto& f=self->f;
self->r = f();
return Foo{}; // whatever
},
p
);
auto r=data->r;
delete data;
return r;
}
Now, the r is assigned instead of constructed. But the core of the idea -- that you pass the fancy callable in the void*, andmthe function unwraps it and interacts with it, and done is there.
In a real thread on pthread, you'd pass a pointer-to-std::thread-state to the pthread invoker. It would set whatever up, invoke the stored procedure, and when done would take the return value and store it in the internal std::thread state (if needed). Then you could get that data by interacting with the internal std::thread state.
Or something else roughly equivalent.