如何创建一个运行抽象类成员函数的 std::thread?

Mci*_*anM 2 polymorphism virtual multithreading templates c++11

我有一些事情:

class Parent
{
private:
    std::thread t1;
protected:
    void ThreadFunction()
    {
        while(true)
        {
            SpecializedFunction();
        }
    }
    void CreateThread()
    {
        t1 = std::thread(&Parent::ThreadFunction, *this);
    }
    virtual void SpecializedFunction() = 0;
public:
    void Run()
    {
        CreateThread();
    }
}

class Child1 : public Parent
{
protected:
    void SpecializedFunction()
    {
        //code
    }
}

class Child2 : public Parent
{
protected:
    void SpecializedFunction()
    {
        //code
    }
}
Run Code Online (Sandbox Code Playgroud)

但是我有编译错误(如果我评论线程创建行,它就会编译)。它说它不能专门化衰变方法。我认为问题要么是 Parent 是抽象的,要么是线程函数受到保护,但我不确定。你能提出一个解决方法/解决方案吗?

谢谢!

Jon*_*ely 5

    t1 = std::thread(&Parent::ThreadFunction, *this);
Run Code Online (Sandbox Code Playgroud)

这将创建副本*this并在副本上运行成员函数。在您失败的情况下,因为您无法创建抽象类的副本,但无论如何制作副本可能不是您想要的。

要在现有对象上运行线程,请传递一个指针:

    t1 = std::thread(&Parent::ThreadFunction, this);
Run Code Online (Sandbox Code Playgroud)

或(自LWG 2219决议以来)参考:

    t1 = std::thread(&Parent::ThreadFunction, std::ref(*this));
Run Code Online (Sandbox Code Playgroud)

正如 TC 在上面的评论中所说,您必须确保在新线程仍在运行时对象的生命周期不会结束。你可以通过在析构函数中加入它来做到这一点:

~Parent() { if (t1.joinable()) t1.join(); }
Run Code Online (Sandbox Code Playgroud)

(如果您std::thread在销毁之前不加入,您的程序将立即终止!)

这仍然不太安全,因为它仅确保在线程仍在运行时类不会被销毁,但线程可能正在访问派生类,因此您可能需要确保线程加入派生析构函数。

  • `std::ref` 版本取决于 LWG 2219。 (2认同)