my simple test code is as:
// t.cpp
#include <iostream>
#include <thread>
#include <chrono>
class test
{
private:
public:
void fcn1();
void fcn2();
uint8_t i = 0;
};
void test::fcn1()
{
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(999));
std::cout << "hihi " << (float)i << std::endl;
}
}
void test::fcn2()
{
std::cout << "yoyo " << (float)i << std::endl;
}
test t;
std::thread tt(&test::fcn1, t);
int main()
{
while (true)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
t.fcn2();
}
return 0;
}
compile and run by g ./t.cpp -o t -lpthread; ./t
, result is like
hihi 0
yoyo 0
hihi 1
yoyo 1
hihi 2
yoyo 2
hihi 3
...
i expect the result should be:
hihi 0
yoyo 1
hihi 2
yoyo 3
hihi 4
yoyo 5
...
looks like the cpp thread of instance member-fcn reset the member-variable?
why not the i
is shared by fcn1
and fcn2
?
the demo code is a simplification of my real useage, but faces the same problem,
what's wrong with my code? thanks very much.
CodePudding user response:
From std::thread
:
args_copy...
are objects of typesstd::decay<Args>::type...
and constructed fromstd::forward<Args>(args)....
...
The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g., with
std::ref
orstd::cref
).
So arguments are copied by default, including the this
argument to a pointer-to-member function. You can wrap it in std::ref
to get a reference explicitly.
std::thread tt(&test::fcn1, std::ref(t));
CodePudding user response:
std::thread
makes a copy of all of its constructor arguments. That means that std::thread tt(&test1::fcn1, t)
makes a copy of t
and calls fcn1
on the copy.
To avoid that you need to pass a pointer or std::reference_wrapper
to t
:
std::thread tt(&test1::fcn1, &t);
Note that even with this change your program's behavior is undefined since you have a data race on t.i
. You should use std::atomic<uint8_t>
instead to avoid that race.