Universal references in a thread function - c++

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));

Related

Thread pool in C++ not using references from args

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

Perfect forwarding const ref deduction error

I've written a super simple thread wrapper that takes a function and runs it in a thread and provides a simple mechanism to signal the thread when it's time to quit. The start function looks like
//tw.hpp
class ThreadWrapper
{
public:
// ...snipped ...
template<typename... Args>
bool start(Args&& ... args)
{
ft_ = std::async(std::launch::async, std::forward<Args>(args)... );
return true;
}
};
When I use it for a non-member function, I need to pass in a const ref of the wrapper into the function that is running to provide a handle the function can use to know when to quit:
void lone_worker(const ThreadWrapper& tw)
{
while (!tw.is_quit_requested())
{
std::cout << "working hard alone\n";
sleep(1);
}
}
void nonmember_demo()
{
ThreadWrapper tw;
tw.start(&lone_worker, std::cref(tw)); // the cref is need to avoid hundreds of lines of compiler template puke with no useful error messages
sleep(5);
std::cout << "quitting\n";
tw.request_quit();
}
I was caught off guard when I originally compiled it without using std::cref by literally hundreds of lines of compiler template puke (gcc 8.1.0) and no clear reason. Is there something I haven't done right with the perfect forwarding to require the use of cref? I assume it's partially caused by the class being non-copyable (it contains a std::future), which smells a little since at least I assume no copy should be made in the first place.
Full exampl here: https://coliru.stacked-crooked.com/a/0eb4d6160b44764a
which smells a little since at least I assume no copy should be made in the first place
You assume incorrectly. async mostly just forwards to thread, which starts by executing:
std::invoke(decay_copy(std::forward<Function>(f)),
decay_copy(std::forward<Args>(args))...);
This does copy all the arguments. The point of the reference wrapper is to avoid this copy - instead of copying the ThreadWrapper object (which is noncopyable), you're copying a std::reference_wrapper<ThreadWrapper const> (which is copyable).
From the linked cppreference page for thread:
The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g. with std::ref or std::cref).

Calling a stored function on a different object

This question relates to the DelayedCaller in this answer.
The DelayedCaller binds a function pointer and its arguments and works like a charm as long as the the arguments aren't pointers to things shorter-lived than the DelayedCaller's execution (think string.c_str() of a local variable as argument).
To circumvent this issue I created a storage for problematic arguments handled by a template function scanning the arguments.
What I need now is kinda the opposite: I want the member function to be called on a different object of the same type, by evaluating the the address of the pointer given to the DelayedCaller as an argument.
I currently see two ways to go about this:
std::placeholders: Instead of providing the object when creating the DelayedCaller it is provided with the call method.
a wrapper for the object pointer that dereferences twice (overloading ->).
I favor 2. over 1. (I don't want to have to provide an argument whenever using call()), but there might other options I am not even considering.
Example:
#include <iostream>
#include <string>
#include <functional>
#include <memory>
class MyClass
{
float myFloat;
public:
MyClass(float f):myFloat(f){}
void myFunc(int arg1)
{
std::cout << arg1 << ", " << myFloat << '\n';
}
};
class MyContainer
{
public:
MyClass* object;
};
// DelayedCaller implementation
class DelayedCaller
{
public:
template <typename TFunction, typename... TArgs>
static std::shared_ptr<DelayedCaller> setup(TFunction&& a_func,
TArgs&&... a_args)
{
return std::shared_ptr<DelayedCaller>(new DelayedCaller(
std::bind(std::forward<TFunction>(a_func),
std::forward<TArgs>(a_args)...)));
}
void call() const { func_(); }
private:
using func_type = std::function<void()>;
DelayedCaller(func_type&& a_ft) : func_(std::forward<func_type>(a_ft)) {}
func_type func_;
};
int main()
{
MyContainer container;
MyClass* c1 = new MyClass(45.6);
container.object = c1;
// the next line is the critical one. Instead of myFunc being called
// on the current value of container.object, it should be called on
// the one container.object is holding when caller is called.
auto caller(DelayedCaller::setup(&MyClass::myFunc, container.object, 123));
caller->call();
MyClass* c2 = new MyClass(22.8);
container.object = c2;
caller->call();
delete c1;
delete c2;
return 0;
}
std::reference_wrapper might help, use:
auto caller(DelayedCaller::setup(&MyClass::myFunc, std::ref(container.object), 123));
Demo
How about leaving "binding" to C++ compiler with usage of lambda expression?
auto caller(DelayedCaller::setup([&container] { container.object->myFunc(123);}));
Gives the output:
123, 45.6
123, 22.8
PS. This lambda is directly convertible into std::function<void(void)>, thus DelayedCaller constructor could be public and created without setup function if wanted. If you can edit its implementation of course.
Your really need to understand what std::bind does.
When using std::bind, it will copy(or move respectively if they are respectively r-value, but as a reminder, whether they are moved depend on callable objects and each arguments feed into std::bind respectively)
Next, I'll discuss the situation when there's only one argument, but the rule of it applies to situation where there're more than one arguments respectively.
Both the callable object(which could be pointers to functions or functors) and the arguments into the object of std::function returned by std::bind, so it will never occur the case you asked.
If the argument is not a pointer, or reference, you can just feed the (temporary) objects into sts::bind and the c++ standard promises that it will only be copied or moved, not by reference unless you use std::ref or std::cref to wrap that object.
But if you feed std::unique_ptr or other things that wraps a pointer(or reference as shown in above), you need to consider them as a pointer(reference), not an object(although copy/move choices still occurs)
If the argument is a pointer, then the pointer will be copied into it.
Will, in this case, if the pointer points to a local variable, bingo, then you have one bug to track.
Actually the code you write will work well if (the destructor of the object does not do any damage to the object in the memory, in other word, the object exists after it is destructed, like POD and etc) && (the memory contains the object is not reused by any other objects, when sth like this (another function is called and its local variables occupies the memory of that object and write something to it) happens it is reused).
If the pointer points to sth you allocated on heap and it is not deallocated until your call of the DelayedCaller::cal is done, then there's nothing wrong with you code.
If the pointer is a constant pointer that points to a literal, then it will be all fine.
The case when the argument is a reference is roughly the same as the case when it's a pointer.
Reference: http://en.cppreference.com/w/cpp/utility/functional/bind

Passing a std::shared_ptr to a function object to std::thread

Need to have this Functor live as long as my thread does, so I've created a shared_ptr to it and trying to pass it to std::thread. I've copied the code and list of errors here.
struct Functor
{
std::string greeting;
explicit Functor(std::string _greeting="Hello!"): greeting { _greeting } {}
void operator()()
{
std::cout << greeting << "\n";
}
};
auto main() ->int
{
std::shared_ptr<Functor> fp = std::make_shared<Functor> ();
std::thread t(&fp);
t.join();
return 0;
}
List of errors:
Error C2893 Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)' std_threads C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\thr\xthread 240
Error C2672 'std::invoke': no matching overloaded function found std_threads C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include\thr\xthread 240
I'm new to c++11 and concurrency. Please help me understand the following
1>does a std::thread always invoke the operator() inside an object when passed by value ? If so, why it has been defined so.
2>how to ensure that a resource given to a thread stays around as long as the thread does?
3>is the Functor written here, a function object ?
4>What have I done here in this code ?!
1>does a std::thread always invoke the operator() inside an object
when passed by value ? If so, why it has been defined so.
std::thread invokes std::invoke. From cppreference, if the first argument is neither a pointer to member function nor a pointer to data member; it is treated as a function object.
So, fp() will be called.
INVOKE(f, t1, t2, ..., tN) is equivalent to f(t1, t2, ..., tN) (that
is, f is a FunctionObject)
So you can basically do std::thread t{*fp}
2>how to ensure that a resource given to a thread stays around as long
as the thread does?
You can have shared_ptr to provide ownership of a shared object. Or you can just manually do it by ensuring the resource passed is in scope. The mileage varies.
3>is the Functor written here, a function object ?
Yes. A FunctionObject type is the type of an object that can be used on the left of the function call operator. However fp is not. But *fp is.
4>What have I done here in this code ?!
You can make it work by explicitly passing Functor::operator() with argument fp.get(). Ofcourse a simple way is to just pass *fp
Demo
std::shared_ptr<Functor> is not callable - it doesn't implement operator(), even while Functor does.
What's the purpose of shared_ptr here? Why not simply
int main() {
Functor f;
std::thread t(std::ref(f));
t.join();
return 0;
}
If for some reason you insist on having Functor instance managed by a shared_ptr, here's one way:
int main() {
std::shared_ptr<Functor> fp = std::make_shared<Functor> ();
std::thread t([fp]() { (*fp)(); });
t.join();
return 0;
}
You can still make std::thread take ownership of your smart pointer with this syntax:
std::shared_ptr<Functor> f = std::make_shared<Functor>();
std::thread thread (&Functor::operator(), f);
thread.detach();
If the first argument is a member function pointer, then the second argument is expected to be a reference or pointer to an instance of the class and std::shared_ptr<Functor> is accepted. When the thread finishes, the smart pointer will be deleted.
Downside: removes the benefit of having a functor because you have to specify the member function.

std::bind binds "by value", is that true?

I just wonder whether the following class will work properly. What I'm a bit scared of is the fact that in the constructor, on the marked line, I bind to values which are just (temporary) arguments. So the question is: Does std::bind take the arguments by-value? To me, this is not clear in the documentations I read.
class BoundFct {
public:
BoundFct(function<void(int, int)> fct, int v){
boundFct = bind(fct, v, _1); // ** PROBLEM HERE ? **
}
void call(int i){
boundFct(i);
}
private:
function<void(int)> boundFct;
};
As far as I tested, it works as intended. But is it a safe approach that will work properly in any case?
From std::bind:
The arguments to bind are copied or moved, and are never passed by reference unless wrapped in std::ref or std::cref.
There's nothing unsafe about your code. Though it'd be better to take any function in your BoundFct constructor, rather than a std::function<>.