Reputation: 123
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!
Upvotes: 0
Views: 427
Reputation: 23527
According to std::bind
documentation:
The return type of
std::bind
holds a member object of typestd::decay<F>::type
constructed fromstd::forward<F>(f)
, and one object per each ofargs...
, of typestd::decay<Arg_i>::type
, similarly constructed fromstd::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
Upvotes: 1