如何使用多态管理线程资源? (C ++)

问题描述 投票:0回答:1

我试图实现多态,其中派生类实现在单独的线程中运行的方法:

#include <memory>
#include <thread>
#include <chrono>

class Base
{
public:
    std::thread m_jobThread;

    ~Base() { if (m_jobThread.joinable()) m_jobThread.join(); }

    virtual void doJob() = 0;
    void doJobInBackground() { m_jobThread = std::thread(&Base::doJob, this); }
};

class Drived : public Base
{
public:
    Drived() = default;
    virtual void doJob() final { std::this_thread::sleep_for(std::chrono::seconds(1)); }
};

int main(int argc, char const *argv[])
{
    Drived d;
    d.doJobInBackground();
    return 0;
}

如何在没有获得pure virtual method called异常的情况下安全地实现此目的?

我希望能够在作业发生时销毁派生对象,并让基类的析构函数处理管理线程。但是由于派生类的vtable在运行基类的析构函数之前被销毁,我得到一个纯虚方法异常。

我想在派生类的析构函数中添加一个stop方法,以确保线程被连接。但这违背了我的多态设计的目的,我希望派生类只负责定义doJob方法,而不是直接或间接处理基类的资源,如线程......

任何想法,如果这是可能的?我需要改变我的设计吗?

c++ multithreading polymorphism virtual-functions
1个回答
1
投票

正如Sam Varshavchik在上面的评论中所指出的,你在这里触发纯虚函数调用的原因是d的析构函数在你的第二个线程开始执行之前运行。您只能在Base析构函数中同步。然而,当Base析构函数运行时,对象的Derived部分已经被破坏。此时对象的动态类型只是Base,因为所有这些仍然存在,因此,虚函数调用将调度到基本版本,这是纯粹的。严格来说,你实际上在这里有未定义的行为,因为对象在一个线程中被销毁而另一个可能在其上调用方法违反了[basic.life]/7.2。当析构函数调用启动[basic.life]/1.3时,对象的生命周期结束,第二个线程中的方法调用不会在第一个线程中调用析构函数inter-thread happen before ...

只是

#include <thread>
#include <chrono>

class Base
{
    std::thread m_jobThread;

public:
    void join() { if (m_jobThread.joinable()) m_jobThread.join(); }

    virtual void doJob() = 0;
    void doJobInBackground() { join(); m_jobThread = std::thread(&Base::doJob, this); }
};

class Derived : public Base
{
public:
    virtual void doJob() final { std::this_thread::sleep_for(std::chrono::seconds(1)); }
};

int main(int argc, char const* argv[])
{
    Derived d;
    d.doJobInBackground();
    d.join();
    return 0;
}

工作良好…

© www.soinside.com 2019 - 2024. All rights reserved.