理解std :: thread语义与worker函数作为类成员

时间:2016-02-04 21:34:20

标签: c++ multithreading c++11

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

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()成员中的向量中,则该对象将在析构函数上挂起。 即使在向量中没有真正的线程,只是在没有外部连接的情况下启动它并尝试通过析构函数来阻止它

1 个答案:

答案 0 :(得分:2)

当然,一旦在this方法中有run指针,就可以通过此指针访问类成员。我猜你的代码的问题是在任何其他成员被初始化之前产生线程,因为它是你的类定义中的第一个成员。我怀疑使用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);
    }
};