lundi 26 août 2019

[lambda][concurrency] Member function captured by lambda asynchronously dispatch issue

guys. As we know, if we have a lambda that captures class members and the lambda is called asynchronously after the class object is released, then it should crash. But if the lambda captures "this", and call this->memFunc() after the class object is released, seems it works ok. I can not understand why it doesn't crash. see code v1.

v1:
class A:
{
public:
    int func()
    {
        std::ofstream myfile("example.txt");
        if (myfile.is_open())
        {
            myfile << "Write from child thread.\n";
            myfile.close();
        }
        else
        {
            std::cout << "Unable to open file";
        }
    }

    void detach()
    {
        std::thread t([this]() {
            std::this_thread::sleep_for(std::chrono::milliseconds(3000));
            func();
        });
        t.detach();
    }
};

int main()
{
    {
        A a;
        a.detach();
    }

    std::cout << "main end" << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    return 0;
}

=======================================================================
v2:
#define RETURN_FROM_LAMBDA_IF_DEAD(x) \
    auto sharedThis = x.lock(); \
    if(!sharedThis) \
        return;

class A: public std::enable_shared_from_this<A>
{
public:
    int func()
    {
        std::ofstream myfile("example.txt");
        if (myfile.is_open())
        {
            myfile << "Write from child thread.\n";
            myfile.close();
        }
        else
        {
            std::cout << "Unable to open file";
        }
    }

    void detach()
    {
        std::thread t([weakThis = weak_from_this(), this]() {
            RETURN_FROM_LAMBDA_IF_DEAD(weakThis);
            std::this_thread::sleep_for(std::chrono::milliseconds(3000));
            func();
        });
        t.detach();
    }
};

int main()
{
    {
        A a;
        a.detach();
    }

    std::cout << "main end" << std::endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(5000));
    return 0;
}

class A has a member function detach() that will create a child thread. The child thread accepts a lambda in which A's member function func() will be called.

When main thread prints "main end", the object a should be released, so when its child thread calls a's func(), it should crash. But a's func() runs ok and "example.txt" created successfully.

Why a's func() can be called even after a has been released?

To make sure a has been released when the child thread call func(), I add weak pointer check, see code v2.

This time, the child thread returns from lambda directly and does not call func(). It means object a indeed has been released when the child thread initiates to run.

Could anyone help give some instructions? Thanks

Aucun commentaire:

Enregistrer un commentaire