Can the example below make undefined behavior and crash when main thread try to call SetX
, because, although x
property is not being accessed in new thread, but object
itself is?
class Object{
public:
int x;
int y;
Object(int x, int y)
{
this->x = x;
this->y = y;
}
void SetX(int x)
{
this->x = x;
}
}*object = nullptr;
int *value_only = nullptr;
void ch()
{
while(true) // assume there is some mechanism to quit loop
{
//with obj variable
//readonly
auto link = obj;
auto y = obj->y;
//write
obj->y = 5;
//without obj variable
//read
auto yy = *value_only;
//write
*value_only = 2;
// note that obj->x is not touched
}
}
int main()
{
obj = new Object(1,2);
value_only = &obj->y;
thread th(ch);
obj->SetX(4);
// assume, th termination is handled
return 0;
}
CodePudding user response:
No there is no issue with accessing two different members of the same object.
Note that both members are public and the setter doesn't do anything but set the member. Hence, you could rewrite ch
to take a reference to obj->y
as parameter and also in main, rather than calling SetX
it could use int& x = obj->x;
. Maybe then it is more obvious that the two threads do not actually share data.
In the thread you copy obj
but that merely copies the pointer.
However, your program will crash due to not joining the thread. std::thread
calls std::terminate
when not joined (or detached) in its destructor. In any case you leak the memory of obj
. While leaking memory on return from main
is not a big deal, obj
may manage other resources (files, db connections, etc) that need to be properly closed in the destructor.
CodePudding user response:
My comments in code :
#include <future>
#include <mutex>
class Object
{
public:
Object(int x, int y) :
m_x{ x },
m_y{ y }
{
}
void SetX(int x)
{
m_x = x;
}
int GetX()
{
return m_x;
}
private:
int m_x;
int m_y;
};
int main()
{
auto obj_ptr = std::make_shared<Object>(1, 2);
// capture obj_ptr by value, making a copy of shared_ptr will increase its
// reference count. When the lambda finishes the shared_ptr will decrease the reference count.
auto future = std::async([obj_ptr]
{
obj_ptr->SetX(3);
});
// destructor of the future will block until async is complete
// so no race condition at shutdown
return 0;
}