Home > OS >  why cpp thread of instance member-fcn reset the member-variable?
why cpp thread of instance member-fcn reset the member-variable?

Time:12-14

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 types std::decay<Args>::type... and constructed from std::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 or std::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);

Demo


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.

  • Related