异步调用 class 函数时出现分段错误

Segmentation Fault when calling class functions in async

我是 c++ 的初学者,正在研究动态内存和异步函数,我不确定为什么以下代码不起作用。

我想做的是基本上动态创建一个 Loop 的对象和一个调用该对象的 start 方法的异步函数,每个分配给不同的映射变量具有相同的id 作为两者的键(示例代码中的randomthing)。

预期:每秒打印出数字 10 到 1。

结果:分段错误

#include <iostream>
#include <vector>
#include <map>
#include <chrono>
#include <future>

class Loop{
    public:
    Loop(int t_):t(t_){}
    void start(){
        while(t>0){
            std::cout << t << std::endl;
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));
            t--;
        }
    }
    
    private:
    int t;
};

int main()
{
    std::map<std::string, std::future<void>> store;
    std::map<std::string, Loop*> storeClass;
    storeClass["randomthing"] = new Loop(10);
    store["randomthing"] = std::async(std::launch::async, [&storeClass](){
        std::cout << "starting" << std::endl;
        storeClass["randomthing"]->start(); 
        std::cout << "finished" << std::endl;
        delete storeClass["randomthing"];
    });
    return 0;
}

我又弄乱了一点,发现这个修改有效:

将存储声明为 std::future<void> store 而不是映射,并在创建 Loop 对象后直接将异步函数分配给它。

为什么示例代码不起作用,为什么修改可以解决问题?

我正在用 -std=c++11 编译程序。

您必须确保所有变量在使用时在生命周期内有效。您的代码:

    std::async(std::launch::async, [&storeClass](){
        storeClass["randomthing"]->start(); // uses storeClass
    });
    return 0;
} // calls storeClass destructor

存在竞争条件,其中 storeClass 析构函数和 storeClass 的使用未排序。结果,当 destructor 恰好在 async 之后被调用时,那就没问题了,否则你会得到一个 seg fault。

不要使用原始指针 - 使用 std::unique_ptr 作为 Loop*

要解决它,您可以将 storeClass 设为 std::shared_ptrunique_ptr 并 copy/move 将其放入 async 中的 lambda 运行。或者等待异步完成:

    store["randomthing"] = std::async(std::launch::async, [&storeClass](){
         .. use storeClass ..
    });
    store["randomthing"].wait(); // wait for calling `storeClass["randomthing"]
    return 0; 
} // will destroy storeClass