【问题标题】:How do I create an std::thread that runs a member function of an abstract class?如何创建运行抽象类成员函数的 std::thread?
【发布时间】:2015-12-19 05:42:58
【问题描述】:

我有一些类似的东西:

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
    }
}

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

谢谢!

【问题讨论】:

  • 删除*,但要注意生命周期问题。

标签: multithreading templates c++11 polymorphism virtual


【解决方案1】:
    t1 = std::thread(&Parent::ThreadFunction, *this);

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

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

    t1 = std::thread(&Parent::ThreadFunction, this);

或者(因为LWG 2219的决议)一个参考:

    t1 = std::thread(&Parent::ThreadFunction, std::ref(*this));

作为 T.C.在上面的评论中说,您必须确保在新线程仍在运行时对象的生命周期不会结束。您可以通过将其加入析构函数来做到这一点:

~Parent() { if (t1.joinable()) t1.join(); }

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

这仍然不是很安全,因为它只确保 base 类在线程仍在运行时不会被破坏,但线程可能正在访问派生类,因此您可能需要确保线程在派生的析构函数中加入。

【讨论】:

  • std::ref 版本取决于 LWG 2219。
  • @T.C.是的,我真的应该记得,因为我报告了它!
  • 您可以将join() 委托给派生的析构函数而不是基析构函数,因为连续调用join() 会引发invalid_argument 异常,这正是C++ 在遍历类层次结构时会执行的操作调用析构函数。
  • @Zenul_Abidin 我不确定您所说的“C++ 在遍历类层次结构时究竟会做什么”。为什么会抛出invalid_argument?基本析构函数可以执行if (t1.joinable()) join();,因此只有在派生析构函数尚未执行此操作时才会加入。
  • @JonathanWakely 我的意思是在基础析构函数中,如果您不使用之前评论中的构造来检查线程是否已经加入,那么当您在基础析构函数中 join() 时,它会抛出invalid_argument(因为它已经加入了派生的析构函数)。
猜你喜欢
  • 1970-01-01
  • 2017-08-29
  • 2019-09-13
  • 2018-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-26
  • 1970-01-01
相关资源
最近更新 更多