Passing a std::shared_ptr to a function object to std::thread - c++

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.

Related

Start std::thread in member function of object that does not have a copy constructor

I want to start a std::thread at a member function of an object that does not have a copy constructor. The standard way of starting a thread at a member function (see for example Start thread with member function) needs a copy constructor. I thought I could get around this by using std::ref (see for example std::thread pass by reference calls copy constructor), but no luck.
Here is my code. Thread t1 works, but not t2. If I try to uncomment the two lines, it gives:
error: attempt to use a deleted function
__invoke(_VSTD::move(_VSTD::get<0>(__t)), _VSTD::move(_VSTD::get<_Indices>(__t))...); ^
/Library/Developer/CommandLineTools/usr/bin/../include/c++/v1/thread:357:5: note:
in instantiation of function template specialization
'std::__1::__thread_execute<void (Dummy::*)(), std::__1::reference_wrapper<Dummy> , 1>'
requested here __thread_execute(*__p, _Index()); ^
etc.
How do I start the thread directly at print(), without needing uselessFunction?
Also, I'd like to understand the error better. Which "deleted function" is the compiler complaining about?
#include <iostream>
#include <thread>
using std::cout;
using std::endl;
class Dummy {
public:
std::atomic<bool> flag; // atomic kills implicitly created copy constructor
void print() { std::cout << "hello!" << std::endl; }
};
void uselessFunction(Dummy &d) {
d.print();
}
int main() {
Dummy d{};
std::thread t1(uselessFunction, std::ref(d)); // this works
// std::thread t2(&Dummy::print, std::ref(d)); // does not work
t1.join();
// t2.join();
}
std::thread use std::invoke to call the function. std::invoke is smart enough to be able to take a pointer to an object and call a member function with it. That means you can change t2 to
std::thread t2(&Dummy::print, &d);
and get the correct behavior.

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

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

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 lambdas to std::thread and calling class methods

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.