Lambda捕获的成员函数异步调度问题

时间:2019-08-26 08:54:06

标签: c++11 asynchronous lambda concurrency

我们知道,如果我们有一个捕获类成员的lambda,并且在释放类对象之后异步调用了lambda,则它应该崩溃。但是,如果lambda捕获“ ​​this”,并在释放类对象后调用this-> memFunc(),则它似乎可以正常工作。我不明白为什么它不会崩溃。参见代码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;
}

A类具有成员函数detach(),它将创建一个子线程。子线程接受一个lambda,其中将调用A的成员函数func()。

当主线程打印“ main end”时,应释放对象a,因此当其子线程调用a的func()时,它应崩溃。但是a的func()运行正常,并且成功创建了“ example.txt”。

为什么即使a被释放后仍可以调用a的func()?

为确保子线程调用func()时已释放a,我添加了弱指针检查,请参见代码v2。

这一次,子线程直接从lambda返回,并且不调用func()。这意味着当子线程启动运行时,对象a确实已被释放。

有人可以帮忙做些指示吗?

0 个答案:

没有答案