了解 std::线程语义,其中工作器函数作为类成员



为了在构造对象启动实际工作的背景线程时实现逻辑,我使用了这样的模式(简化):

class A {
    std::thread t{&A::run, this};
    std::atomic_bool done;
    // variables are the question about
    std::vector<std::thread>  array_for_thread_management;
    // ... and other members
protected:
    void run() {
        ...
        array_for_thread_management.push_back([](){...});
        ...
   }
public:
    A() = default;
    // all other constructors deleted because of used 
    // some members like std::atomic_bool done;
    ~A() {
        done = true;
        bi::named_condition         cnd{bi::open_only, "cnd"};
        cnd.notify_one();
        if (t.joinable())
            t.join();
        for(std::thread& worker : array_for_thread_management) {
            if (worker.joinable()) worker.join();
        }
    }

};

如果我在主后台线程中添加子线程推送到 run() 成员中的向量中,则对象将挂在析构函数上。即使向量中没有真正的线程,只是在没有外部连接的情况下启动它,并尝试通过析构函数阻止它

当然,一旦在 run 方法中有了指针this就可以通过此指针访问类成员。我想你的代码的问题在于线程是在初始化任何其他成员之前生成的,因为它是类定义中的第一个成员。我怀疑使用以下class A定义,您在访问成员变量时不会有任何问题:

class A {
    std::atomic_bool done;
    // variables are the question about
    int i;
    std::string s;
    std::vector<std::string> v;
    // and only after everything above is initialized:
    std::thread t{&A::run, this}; // spawn a thread
    // ...
}

但是,就我个人而言,我更喜欢有一个单独的方法start()该方法生成一个线程,而不是在类构造函数中隐式生成它。它可能看起来像这样:

class A
{
    std::unique_ptr<std::thread> t;
    std::atomic<bool> some_flag;
public:
    void start()
    {
        t.reset(new std::thread(&A::run, this));
    }
private:
    void run()
    {
        some_flag.store(true);
    }
};

最新更新