Passing lambdas to std::thread and calling class methods - c++

I'm having a bit of trouble using std::thread together with lambdas. I have a method TheMethod where I should use std::thread to parallelize some function calls to methods in the same class.
I define a lambda function, and try to pass it as follows to the std::thread instance I create:
auto functor =
[this](const Cursor& c, size_t& result) ->void {result = classMethod(c);};
size_t a;
Cursor cursor = someCursor();
std::thread t1(functor, cursor, a);
t1.join();
Unfortunately, the compiler gives me:
/usr/include/c++/4.8/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of<TheMethod...
I tried a lot of combinations in the lambda definition, and in the way of calling the std::thread constructor, but I get the same error always. The thread library is included, I link pthread too.
Thanks for hints!

You can use std::ref to pass the parameters by reference:
std::thread t1(functor, std::ref(cursor), std::ref(a))
You could also capture the parameters by reference in the lambda itself:
size_t a;
Cursor cursor = someCursor();
std::thread t1([&] {a = classMethod(cursor);});
t1.join();

This is because the objects cursor and a are passed by value to the constructor of thread. The functor takes a reference to the local copies of the newly created thread and not on the objects you expected them to be.
Hence, as answered by "alexk7", you should use std::ref or if you want to capture them pass by reference.

Related

pass a lambda that captures a unique_pointer

I'm using lambda generalized capture to move a unique_ptr into a lambda (https://stackoverflow.com/a/16968463/118958). I want to pass this lambda elsewhere to set a callback function, but I'm not sure how.
Here's a small example with what I'm trying to do that fails to compile:
void set_callback(std::function<void(void)> cb);
void move_callback(std::function<void(void)> &&cb);
void test() {
auto a_ptr = std::make_unique<int>(10);
auto lambda = [a_ptr = std::move(a_ptr)] () {};
// set_callback(lambda); // I understand why this wouldn't work
move_callback(std::move(lambda)); // but I would expect this to be OK
}
Any idea on how to do something like the above?
std::function must be both CopyConstructible and CopyAssignable, which means that it must be able to copy its target. Unfortunately, since your lambda is not copyable, you cannot store it in a std::function.
You will have to resort to another implementation of callable type-erasure that works with movable-only objects.

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

How to pass a lambda-function-variable with arguments to std::thread? [duplicate]

I'm having a bit of trouble using std::thread together with lambdas. I have a method TheMethod where I should use std::thread to parallelize some function calls to methods in the same class.
I define a lambda function, and try to pass it as follows to the std::thread instance I create:
auto functor =
[this](const Cursor& c, size_t& result) ->void {result = classMethod(c);};
size_t a;
Cursor cursor = someCursor();
std::thread t1(functor, cursor, a);
t1.join();
Unfortunately, the compiler gives me:
/usr/include/c++/4.8/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of<TheMethod...
I tried a lot of combinations in the lambda definition, and in the way of calling the std::thread constructor, but I get the same error always. The thread library is included, I link pthread too.
Thanks for hints!
You can use std::ref to pass the parameters by reference:
std::thread t1(functor, std::ref(cursor), std::ref(a))
You could also capture the parameters by reference in the lambda itself:
size_t a;
Cursor cursor = someCursor();
std::thread t1([&] {a = classMethod(cursor);});
t1.join();
This is because the objects cursor and a are passed by value to the constructor of thread. The functor takes a reference to the local copies of the newly created thread and not on the objects you expected them to be.
Hence, as answered by "alexk7", you should use std::ref or if you want to capture them pass by reference.

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.

boost::bind thread for pointer to function with argument

I have a function foo(myclass* ob) and I am trying to create a consumer thread using consumer_thread(boost::bind(&foo)(&ob))
The code does not compile which I believe is due to my inappropriate way of passing the function argument to the function pointer.
class myclass{
// stuff
}
void foo(myclass* ob){
// stuff
}
int main(){
myclass* ob = new myclass();
boost::thread consumer_thread()boost::bind(&foo)(&ob));
// stuff
}
What am I doing wrong? Can anyone here elaborate on boost::bind and how to pass function pointers with function arguments?
Thanks in advance!
Your code sample has some errors. This is a fixed version, where the return value of the call to bind is used as the sole parameter in the boost::thread constructor:
boost::thread consumer_thread(boost::bind(foo, ob));
But you can skip the call to boost::bind entirely, passing the function and its parameters to the constructor:
boost::thread consumer_thread(foo, ob);
That should be bind(foo, ob).
However, I'm fairly sure that boost::thread has the same interface as std::thread, in which case you don't need bind at all:
boost::thread consumer_thread(foo, ob);