Access a Variable of an Object from Threads - c++

I need help with my c++ programm.
I start to Threads beside the main function:
thread Thread1(&Foo::Loop1, info,std::ref(info));
thread Thread2(&Foo::Loop2, info,std::ref(info));
info is an object from the class Foo which contains bool active
later I change the active to true but the value in Loop1 or Loop2 dont change. They are everytime the same.
my prototype function looks like this:
void Loop1(Foo info);
void Loop2(Foo info);
the called function:
void Foo::Loop1(Foo info){
while (true){
if (info.active){
//Stuff
}
}
}
So what should I do to pass the value from the object Foo which change in the main function so the value active in the Loop functions are equal.
Thank you for helping :)

If the functions are static members, they should have a reference parameter, Foo&.
void Loop1(Foo& info);
void Loop2(Foo& info);
otherwise the threads get copies of the object you passed.
If they are non-static members you don't need to pass the instance at all:
void Foo::Loop1(){
while (true){
if (active){
//Stuff
}
}
}
thread Thread1(&Foo::Loop1, info);
thread Thread2(&Foo::Loop2, info);

std::ref returns an std::reference_wrapper<T> which is implicitly convertable to T& via its conversion operator. When you pass an std::reference_wrapper<T> to a function which accepts a T by value, the conversion operator is invoked, and the function's local copy of T is constructed via its copy constructor.
#include <functional>
class Object
{
// ...
};
void Func(Object obj)
{
// Some code which modifies obj
}
int main()
{
Object obj;
Func(std::ref(obj)); // <-- Conversion operator invoked, obj passed by value
}
Change the functions to accept Foo by reference.

Related

In C++, How a std::thread can call a member function without creating an object?

If we have a class H with some operator() overloaded. How it is possible to create a thread from these member functions without instantiating an object from class H. Consider the following code
#include<iostream>
#include<thread>
class H {
public:
void operator()(){
printf("This is H(), I take no argument\n");
}
void operator()(int x){
printf("This is H(), I received %d \n",x);
}
};
int main(){
int param = 0xD;
//No object created
std::thread td_1 = std::thread(H());
std::thread td_2 = std::thread(H(),param);
td_1.join();
td_2.join();
//From an object
H h;
std::thread td_3 = std::thread(h);
std::thread td_4 = std::thread(h,param);
td_3.join();
td_4.join();
return 0;
}
produce the output :
This is H(), I take no argument
This is H(), I received 13
This is H(), I take no argument
This is H(), I received 13
The question is, how td_1 and td_2 called the member function operator() of class H without an object of class H?
how td_1 and td_2 called the member function operator() of class H without an object of class H?
td_1 and td_2 does create objects of type H. Those objects are temporaries. Next, those supplied function object(which are temporaries in this case) are moved/copied into the storage belonging to the newly created thread of execution and invoked from there.
You can confirm this by adding a default constructor and move constructor inside class H as shown below:
#include<iostream>
#include<thread>
class H {
public:
void operator()(){
printf("This is H(), I take no argument\n");
}
void operator()(int x){
printf("This is H(), I received %d \n",x);
}
//default constructor
H()
{
std::cout<<"default constructor called"<<std::endl;
}
//move constructor
H(H&&)
{
std::cout<<"move constructor called"<<std::endl;
}
};
int main(){
int param = 0xD;
std::thread td_1 = std::thread(H());
std::thread td_2 = std::thread(H(),param);
td_1.join();
td_2.join();
return 0;
}
The output of the above program is:
default constructor called
move constructor called
move constructor called
default constructor called
move constructor called
move constructor called
This is H(), I take no argument
This is H(), I received 13
Consider this function:
void f() {
printf("This is f(), I take no argument\n");
}
A thread that calls the function is constructed like std::thread(f). Code like std::thread(f()) is invalid, because the parameter of std::thread must be callable (in this case, a function object). If you call the function before passing it to the constructor, std::thread can no longer call it.
So you pass f to the constructor, and it later becomes f(), and the function is called.
Similar to passing the name of a function, you can pass an object to the constructor, and the thread later calls operator(). When you write std::thread(H()), you construct a temporary object. Because class H has operator(), this code is accepted.
In fact, std::thread(H{}) is also accepted. This shows that the parentheses refer to the constructor H::H(), rather than H::operator(). You did not write a constructor for the class, but the compiler creates a default constructor.
You could also use this code to construct a temporary object with H() and immediately call operator():
int main() {
H()(); // Valid: H() is callable
//f()(); // Invalid: f() is not callable
}
The syntax H() is creating a temporary object of type H in this context. The temporary object is passed to the std::thread constructor.
Now, if the thread were to call operator() on that temporary, that would be a problem, since the temporary will only live until the end of the line std::thread td_1 = std::thread(H()); and the thread function may execute after that.
However, the thread doesn't actually use that temporary. Instead a new object of the (decayed) argument type is created for the thread, copied/moved from the temporary object you gave to the constructor. This H object lives until the thread exits and on this object operator() is called.

What does std::move do when called on a function?

I'm working on making some changes to a piece of code, and have a doubt in understanding the behavior of std::move in below case:
struct Timer {
Timer (boost::asio::io_service& ios) : timer_{ios} {}
boost::asio::steady_timer timer_;
};
struct TimerContext {
void *ctxt_;
};
class A {
std::function<void(Timer *, const TimerContext&)> callback_;
boost::asio::io_service ios_;
};
A's constructor:
A::A (std::function<void(Timer *, const TimerContext&)> cb) : callback_{std::move(cb)}
{
}
The callback function definition:
void
customCallback (Timer *timer, const TimerContext& ctxt) {
...
}
In main(),
for (int i = 0; i < 5; ++i) {
A *a = new A{customCallback};
}
My doubt is for this line:
A::A (std::function<void(Timer *, const TimerContext&)> cb) : callback_{std::move(cb)}
Class A is getting instantiated in a loop, and the same customCallback function is getting moved to the custom constructor for each new object.
Will the first std::move not make callback function unusable for next call? As I understood, if you use std::move(t), then t cannot be used again in that scope.
I'm confused what is happening internally here for all 5 calls to std::move(cb) on the same function in new A. Is this the right way to do how it is implemented?
Look carefully at A's constructor:
A::A (std::function<void(Timer *, const TimerContext&)> cb)
The function, cb is being passed by value. That means a copy of the function has already occurred from when it was invoked via new:
A *a = new A{customCallback};
The std::move in the constructor initializer list exists to avoid a redundant copy into the member variable. The original function defined by the caller who invoked new A remains unmoved. This is preferred because copying a std::function variable can be expensive. (sizeof(cb) - might be way bigger than you expected).
An alternative implementation: The function could have been passed as a const reference and allow the copy to occur in the constructor itself:
A::A (const std::function<void(Timer *, const TimerContext&)>& cb) : callback_{cb}
Your constructor A::A (std::function<void(Timer *, const TimerContext&)> cb) takes its parameter by value, i.e. customCallback is first copied into cb, then moved from that copy into callback_.
So every time the constructor is called, the copy is moved from, not the original customCallback object.
Also, you should avoid using raw calls to new and prefer smart pointers instead to avoid memory leaks, but that was not the question at hand here :-)

how to pass in a std::shared_ptr but do "pass by reference" job?

I have a main function that takes in a reference of a class object and try to update it via foo() and bar(), however, the bar() only allows to pass into a shared_ptr type. How can I guarantee it behaves as expected, assuming I am NOT allowed to modify the signature of bar().
void foo(MyStruct& s) {
modifyS(s);
}
void bar(std::shared_ptr<MyStruct> s) {
modifySAgain(s);
}
mainFunction(MyStruct& s) {
foo(s);
// bar(?) how should I do here such that s would be modified by bar()
// bar(std::make_shared<Mystruct>(std::move(s)) ?
}
You could use a null-aliasing shared pointer:
bar(std::shared_ptr<MyStruct>(std::shared_ptr<MyStruct>(), &s));
The temporary shared pointer created in this call shares ownership with a null shared pointer, so it does nothing on destruction.
This is perhaps a bit of a hack.

Run Member Function in Separate thread

I am trying to run a member function in its own thread and have followed this post, however in that example, the thread starts and finishes in the same function. How do you maintain a reference to the thread to join in a separate member function (say the destructor)? I have tried this:
class foo
{
foo();
~foo();
volatile sig_atomic_t m_run_thread = true;
std::thread &m_read_thread;
void read_thread();
}
foo::foo():m_read_thread(std::thread(&foo::read_thread, this))
{
}
foo::~foo()
{
m_run_thread = false;
m_read_thread.join();
}
void foo::read_thread()
{
while(m_run_thread)
{
//do something cool
}
}
int main()
{
foo bar;
//do other stuff
}
The compiler gives me an error though: error: invalid initialization of non-const reference of type ‘std::thread&’ from an rvalue of type ‘std::thread’. This is caused because I'm trying to bind a temporary to a reference. What's this best way to fix this?
foo::foo():m_read_thread(std::thread(&foo::read_thread, this)) is not going to work as std::thread(&foo::read_thread, this) is a temporary value and a temporary cannot be bound to a non const lvalue reference.
That said there is no reason to make the thread member a reference. You can simple have a std::thread member like std::thread m_read_thread; and then in the constructor you would initialize it like
foo::foo() : m_read_thread(std::thread(&foo::read_thread, this))

Moving semantics of unique_ptr

Lets consider the following piece of code:
template<typename T>
void f(std::unique_ptr<T>&& uptr) { /*...*/ }
In another function:
void g()
{
std::unique_ptr<ANY_TYPE> u_ptr = std::make_unique<ANY_TYPE>();
f(std::move(u_ptr));
X: u_ptr->do_sth(); // it works, I don't understand why. Details below.
}
I don't understand why u_ptr in line X is still alive.
After all I forced him to be moved (std::move).
---EDIT---
Ok, so now:
The code is still working:
class T{
public:
T(){}
void show(){
std::cout << "HEJ!\n";
}
};
void f(std::unique_ptr<T> ref){
ref->show();
}
int main()
{
std::unique_ptr<T> my;
my->show();
f(std::move(my));
my->show(); // How is it possible. Now, f takes unique_ptr by value
return 0;
}
You didn't show us that code to function f, but presumably it didn't move the pointer, even though it had permission to.
You passed the unique_ptr by reference. If function invocation actually moved it, then the function couldn't use it because it would be gone before the function had a chance to.
If you want function invocation to actually move the pointer, you need to pass the pointer by value, not be reference. That value would be a unique_ptr for it to be moved into. In that case, you should declare the function as taking a std::unique_ptr<T> instead of a std::unique_ptr<T>&&. Then you can actually invoke the move constructor when you call the function.
Update: With your latest change, the unique_ptr would no longer reference any valid object due to the move construction. You just never check that it does. Invoking a non-virtual method that doesn't access any member variables can work just the same whether the object is valid or destroyed because it doesn't need anything from the object. You also never made the unique_ptr actually point to anything.
Instead, make the unique_ptr point to something. After it's moved, try calling a virtual function or accessing a member whose value is changed by the destructor. Like this:
#include <iostream>
#include <memory>
class T{
public:
T() : valid (true) {}
~T() { valid = false; }
bool valid;
void show(){
std::cout << "HEJ! " << valid << std::endl;
}
};
void f(std::unique_ptr<T> ref){
ref->show();
}
int main()
{
std::unique_ptr<T> my (new T); // Make it point to a new object
my->show();
f(std::move(my));
my->show(); // Try to access
return 0;
}
in the line f(std::unique_ptr<T>&& uptr) uptr is not an object - it's a reference. a reference which capable to catch temporeries and mutate them.
it's like asking why doesn't the object get cloned in the next example
void func(std::string& str);
std::string str_ = "yyy";
func(str_);
str_ is passed by "regular" reference and won't get copied - this is what pass by reference means.
std::move only cast l-value to r-value-reference, which uptr in f(std::unique_ptr<T>&& uptr) can reference, it's a reference referencing an object. opposed to the common conception, std::move won't do any moving by itself, only casts the object to r-value-reference for the move constructor/assg. operator to kick in.
here, the pointer still holds valid data since it was not moved, only casted to r-value-reference.
if you want the object to move you have to declare the parameter as object, not reference : f(std::unique_ptr<T> uptr)
In your edit, you have undefiend behaviour, so everything may occure.
The reason why your call to show doesn't crash is because it doesn't use the this pointer (it doesn't try to modify or access a data member).
Try this:
class T{
public:
int v;
T(){}
void show(){
v = 0;
std::cout << "HEJ!\n";
}
};
void f(std::unique_ptr&& ref)
This is the answer when you initially had your f function taking a rvalue reference &&.
Your function takes a rvalue reference. Therefore, no new unique_ptr object is created yet, you are simply passing a reference.
Inside your f function, if you create a a local unique_ptr, with the parameter uptr, then finally uptr will be moved to create that new object.
template<typename T>
void f(std::unique_ptr<T>&& uptr)
{
//move uptr into local_unique_ptr
//note that we have to use move again
//because uptr has a name, therefore its a lvalue.
auto local_unique_ptr = std::unique_ptr<T>(std::move(uptr));
}
The important thing to always know is that std::move is simply a static_cast.
If you pass a lvalue to std::move, it returns a rvalue. If you pass a rvalue, it returns a rvalue. That's it.
Your function f may not in fact move the pointer. Merely taking an object by && does not modify the object.
u_ptr->do_sth() may invoke a static member function or a member function that does not access the object (this) and this is why it does not crash.