I was reading concurrency in action and came up with this piece of code. However, i dont quite understand why line<1> is syntax valid. Also, how the order got determined? is it possible to put std::thread t(&my_x, &X::do_lengthy_work); instead? how many inputs can take based on the code over here?
class X
{
public:
void do_lengthy_work();
};
X my_x;
std::thread t(&X::do_lengthy_work,&my_x); //<1> the bood says This code will invoke my_x.do_lengthy_work() on the new thread, because the address of my_x is supplied as the object pointer
I think that you are confused by the syntax here.
This is just a constructor call for an object of type std::thread named t (so the arguments order did not "get determined", it is defined by the constructor signature).
Two parameters are expected by this constructor :
1) A callable : &X::do_lengthy_work , as a pointer to a member function, is a Callable.
2) The arguments expected by the Callable : a member function always has an implicit this argument of type (const) X* : this is why here you pass &my_x, the address of the object on which the Callable will be called.
If you add an argument to do_lengthy_work, then you need to specify it when you construct the thread as well :
class X
{
public:
void do_lengthy_work(int i) {}
};
int main() {
X my_x;
std::thread t(&X::do_lengthy_work,&my_x, 2);
^^^^
}
Also, how the order got determined? is it possible to put std::thread
t(&my_x, &X::do_lengthy_work); instead?
As with any other c++ function order determined by function signature, in this case std::thread constructor signature:
template< class Function, class... Args >
explicit thread( Function&& f, Args&&... args );
from std::thread documentation
As you can see that Function is the first parameter and parameters follow (if any). So you cannot put pointer to class before pointer to method.
Excellent book about the topic !
std::thread t(...); creates a thread object t. The first argument of the constructor must be either the adress of a function, or an executable class (i.e. a class with operator() defined).
For ordinary functions like void f(){... }, it would be sufficient to give its name as first argument f. For member function, you have to give its full name, so here: X::do_lengthy work. But for getting the pointer to the mbmer function an explicit & is required (see C++11 standard, section 5.3.1, pt 4).
The arguments following the first arguments will be given to the function when the thread starts and wants to execute it. In the specific case of member functions, the very first argument will be used to say on which object the function has to be executed.
So roughly speaking thread(&class::member_function, arg1, arg2, ... arg n) will call arg1.member_function (arg2, .... arg n).
Related
I have a member function which I cannot unit test easily (it listens to sockets etc):
void MyClass::func()
{
listen();
send();
}
So I want to template it and then I can pass a mock object in my test:
template<class OBJECT>
void func(OBJECT& obj)
{
obj.listen();
obj.send();
}
and then I'd do:
func(*this);
The above compiles when I do a normal function call. However, when I spawn a thread and call it:
std::thread t1(&MyClass::func, this, *this);
I get compiler errors (see below) referring to decltype. Is there a way I can still achieve this?
/opt/gcc-8.2.0/lib/gcc/x86_64-unknown-linux/8.2.0/../../../../include/c++/8.2.0/thread:127:8: note: in instantiation of template class 'std::thread::_Invoker<std::tuple<void (MyClass::*)(MyClass &),
MyClass *, MyClass> >' requested here
__make_invoker(std::forward<_Callable>(__f),
However, the following works:
void MyClass::x()
{
func(*this);
}
std::thread t1(&MyClass::x, this);
There are two issue in your code:
First, you cannot pass function templates to the std::thread constructor. You must explicitly specify what specialisation of the function template to use, which in this case, would be &MyClass::func<MyClass>.
Second you are trying to pass a reference as an argument to the constructor of std::thread. When the std::thread constructor is called, the first argument is the function to run concurrently, and the others are the argument to the function. The other arguments are moved and then passed as argument to the function. This is fine if the argument is a pointer or a variable, but causes an issue if the function expects a non-const lvalue as an argument.
You can solve both issues by constructing std::thread with lambdas:
std::thread t1([=]{
this->func(*this);
});
Conversely, you could use std::ref, a reference wrapper, in the std::thread constructor, and explicitly specify the function template specialisation:
#include<functional>
std::thread t1(&MyClass::func<MyClass>, this, std::ref(*this));
Personally, I much prefer constructing std::threads with lambdas, as it is cleaner and less error prone.
This question already has answers here:
Start thread with member function
(5 answers)
Closed 4 years ago.
I would like to spawn a thread or a future calling this function:
std::string myClass::myFunction() const noexcept
I first tried spawning them both like this:
thread t0(myFunction); auto f1 = async(myFunction);
I would then get this error:
no instance of constructor "std::thread::thread" matches the argument list. argument types are: (std::string () const)
I then read online that since it is const I would need to call it by reference but all methods online have not worked, I am unsure if the problem is because the function is const or not.
What I have tried:
thread t0(&myClass::myFunction); auto f1 = async(&myClass::myFunction);
and
thread t0(&myFunction); auto f1 = async(&myFunction);
After this I would have two new errors that I cannot find a solution to:
std::invoke: no matching overloaded function found.
and
Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'
I think this is due to my lack of understand on how threads and futures work but I am struggling to find literature that gives me any relation to this.
Basically I don't really understand what rule I am breaking, if there is a fundamental flaw in my approach any direction or tips would be nice. Thank you for your time.
std::string myClass::myFunction() const noexcept
This is not a function. This is a class method. There is a fundamental different between the two.
You cannot simply write
myFunction();
Somewhere in your code, other than in another method of the same class, which uses this to invoke a different method for the same instance of the class. Anywhere outside a method of the same class, myFunction(); won't compile, and your compilation error is the same exact reason. The first parameter to std::thread's constructor is a function, not a class method. It can be a class method, which I'll get to shortly. But your first error is confusion between the concept of a function and a class method, that you need to understand.
You could make myFunction() a static class function, which then works just like any, ordinary, function, and then feed it to std::thread as usual. Another option is to construct std::thread using a wrapper function that passes whichever class whose method you wish to invoke to the wrapper function, and the wrapper function uses it. The "whichever class" could be this:
void invoke_func(const myClass *ptr)
{
ptr->myFunction();
}
// ...
std::thread new_thread{ this };
Another, a more modern approach that can be used to invoke a class method is to pass an additional parameter, a pointer to an instance of the class whose method you wish to invoke:
std::thread new_thread{ &myClass::myFunction, this };
The myFunction() method does not take any parameters here as arguments, but when the first parameter to std::thread's constructor is a class method, and not a function, the first parameter is taken to be a pointer to an instance of the class whose method gets invoked, with the remaining parameters getting forwarded as usual.
But you will need to figure out, on your own, which class's instance you are trying to invoke, whether this, or some other instance of your class.
Although you can often write foo() inside a class to invoke this->foo(), as a shortcut, this is not the case when you're outright "naming" the member function, and that's what you're doing here as you are actually passing a member function pointer to std::thread.
It can work, you just need to supply the object pointer too:
std::thread t0(myFunction, this);
You could pass a pointer to a different myClass instead, if you liked!
I have my own thread implementation which allows me to manage various ways of communicating with my threads. It is based on the C++ std::thread class.
I create the thread to run a function named run() which calls the user function. What I'd like to be able to do is call the user function including my thread object pointer.
There is where I have a problem in the constructor. I want to pass the Args as specified on the constructor and prepend this to that list:
class safe_thread
{
public:
typedef std::shared_ptr<safe_thread> pointer_t;
typedef std::vector<pointer_t> vector_t;
template<class Function, class... Args>
safe_thread(Function&& f, Args&&... args)
: f_function([this, f, args...]{ std::bind(f, this, args...)(); })
{
[...snip...]
private:
std::function<void()> f_function;
};
// I use that constructor with two different types of signatures:
//
// 1. member function
//
safe_thread listen(&my_other_class::some_function, this);
// 2. static function
//
safe_thread worker(&my_static_function);
std::bind() does not understand my current syntax. It expects a function (f) and args.... So, how do I change args... to include this?
For those interested, I actually found a solution which is to move the this parameter to the end of the list. This way my std::invoke() to a member function or a standard static function work alike:
f_function([this, f, args...]{ std::invoke(f, args..., this)(); })
Without that, as mentioned by Miles Budnek, a load of SFINAE would be required to know whether f is a member function or a plain function.
The problem was that in some cases I would create a thread in a member function and in other cases I would create a tread out of a static function.
In case of the member function, the first argument in the args... list is the caller's this and obviously that this can't be moved over as the next parameter.
In effect, my first attempt was generating this:
std::invoke(
&my_other_class::some_func, // correct
safe_thread::this, // wrong 'this' (i.e. safe_thread)
my_other_class::this, // 'this' for function, wrong location
...); // other parameters
By changing the order in my call, I now get the correct 'this' at the correct location:
std::invoke(
&my_other_class::some_func, // correct
my_other_class::this, // 'this' for function, correct location
..., // other parameters
safe_thread::this); // 'this' to safe_thread
Obviously this means I have to fix the signature of the called functions, but I'm fine with that.
As mentioned by tkausl, std::bind() is not required. See comments for details about that. That being said, std::invoke() is C++17, so if you're still on an older version, you'll probably have to stick to std::bind().
I don't understand why the following code compile and works:
template<typename Predicate>
void foo(Predicate p) {
}
bool g(int n) {
}
void user(int n) {
foo(g);
}
foo is supposed to get a function object that will run on a data structure but I made the method simpler, because what I don't understand is how can this works? A method isn't an object. The normal way to do it is to create a new class, override operator() and then send an instance of that class.
Well, in this case the Predicate parameter is substituted by a function pointer of type bool (*func) (int). Nothing wrong with that...
The Predicate template argument can be almost any type. So you can use it for function pointers and classes as well as the basic types.
If you use the function argument p as a function, then it can be anything that is callable, like a function pointer, an object whose class have an operator() member function, a pointer to a static member function, a std::bind object, a std::function object or a lambda expression.
It can't be a pointer to a member function though, because to call a pointer to a member function you need an instance to call it on. For this use std::bind.
I am trying to store pointers to memberfunctions of different Classes in C++. What are the possibilities in C++?
I would like to do this:
class A {
T0 f(T1,T2);
};
class B {
T0 g(T1,T2);
T0 h(T1,T2); //interfaces cant be used since the number of functions per class differs.
};
typedef WHATTOPUTHERE type;
type x;
x = A::f;
x = B::h;
Update: Another Problem is that the code should be continueable like this:
B myB;
myB::x(a,b); //not sure about the syntax, should result in myB::h(a,b) being called
This means that I can not bind at the time I store the pointer, since the instance does not exist (yet).
Function objects to encapsulate your function pointers should work.
boost::function is one option, maybe something like this:
class SomeObj
{
public:
void SetInt(int i);
};
SomeObj myObject;
std::vector<boost::function> memberFuncs;
// in the template arg to boost::bind specify the function type
// _1 here denotes late binding so you can pass whatever value you want when invoked
// you could simply bind a parameter as a variable or literal instead
memberFuncs.push_back(boost::bind<void(int)>(&SomeObj::SetInt, &myObject, _1));
memberFuncs[0](42); // myObject->SetInt(42);
Untested/uncompiled code disclaimer this is just for a general idea.
One possible implementation (using C++11) can easily be done using std::function and a lambda like this:
typedef std::function<void(int)> FunctionType;
SomeClass someClass;
FunctionType func = [&someClass](int argument)
{
someClass.SomeMemberFunction(argument);
};
To have a pointer to Fred::f(char, float) you need this sort of pointer:
int (Fred::*)(char,float)
http://www.parashift.com/c++-faq-lite/pointers-to-members.html
The answer to your particular question is that there is no type that you can add to the typedef and make the code compile. The reason is that member function pointers take a hidden argument of the type of the class form which they are obtained. The type of that hidden argument will be different when you take the address of a member function from A or B.
The next question is whether it makes sense or not from a design perspective, considering that you cannot apply the function pointer A::f to an instance of type B, what is the point of considering member pointers of A and B together?
Now, there are possible workarounds for this particular problem (if it makes sense in your case, but I would first review the design) that involve performing type-erasure on the function pointer to remove the hidden argument and generate an object that is callable with the given set of arguments and return type that is common to all of the member functions. This is already done inside std::function (alternatively boost::function if your compiler does not support C++11), as has been suggested before:
A a_instance;
std::function< T0 (T1,T2) > f( std::bind( &A::f, &a_instance, _1, _2 ) );
T0 r = f( T1(), T2() );
Note that part of the trick is that std::bind binds the member function pointer with the pointer to the instance, filling in the hidden argument, while leaving the other two arguments unbound. At this point, because the result of bind does no longer depend on the type of the first argument, type-erasure can be applied removing A from the type of the resulting object.