如何使用多态管理线程资源?(C++) [英] How to manage thread resource with polymorphism? (C++)

查看:53
本文介绍了如何使用多态管理线程资源?(C++)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试实现多态,其中派生类实现了一个在单独线程中运行的方法:

I am trying to implement polymorphism, where the derived class implements a method that is run in a separate thread:

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

如何安全地实现这一点而不会出现调用的纯虚方法异常?

How do I achieve this safely without getting a pure virtual method called exception?

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

I want to be able to destroy the derived objects, potentially while the job is happening and have the destructor of the base class deal with managing the thread. but since the vtable of the derived class gets destroyed before the destructor of the base class is run, I get a pure virtual method exception.

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

I thought of adding a stop method in the destructor of the derived class that makes sure the thread is joined. But that defeats the purpose of my polymorphic design, where I want the derived class to ONLY be responsible for defining the doJob method and not for directly or indirectly handling the resources of the base class such as the thread...

如果可能的话,有什么想法吗?我需要改变我的设计吗?

Any ideas if this is possible? Do I need to change my design?

推荐答案

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

As pointed out by Sam Varshavchik in his comment above, the reason why you trigger a pure virtual function call here is that the destructor of d is run before your second thread has even started executing. You only synchronize in the Base destructor. By the time the Base destructor runs, however, the Derived part of the object has already been destroyed. The dynamic type of the object at this point is just Base, because that's all that's still alive and, thus, the virtual function call dispatches to the base version, which is pure. Strictly speaking, you actually have undefined behavior here because the object being destroyed in one thread while another may be calling a method on it violates [basic.life]/7.2. The lifetime of your object ends when the destructor call starts [basic.life]/1.3, the method call in the second thread does not inter-thread happen before the destructor call in the first thread…

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

工作正常…

works fine…

这篇关于如何使用多态管理线程资源?(C++)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆