c++ - 最多同步派生的析构函数

标签 c++ multithreading destructor

我在调用纯虚方法时遇到了崩溃,这是由于竞争条件导致其他线程仍在调用已销毁的派生类的方法。这是它的要点:

class Resource
{
protected:
    Resource();
    virtual ~Resource();

public:
    virtual void *lock_shared() = 0;
    virtual void unlock_shared() = 0;

    // Wait for all other threads to finish.
    void sync()
    {
        mutex.lock();
        mutex.unlock();
    }

protected:
    std::shared_mutex mutex;
};

Resource::~Resource()
{
    sync();
}

class Image : public Resource
{
public:
    Image();
    ~Image() override;

    void *lock_shared() override
    {
        mutex.lock_shared();

        return accessData();
    }

    void unlock_shared() override
    {
        processData();

        mutex.unlock_shared();
    }
};

请注意,当 Image 类型的对象被销毁时,其目的是等待所有具有共享访问权限的线程完成。但是,由于 C++ 析构函数调用顺序,Image::~Image() 是在我们 Resource::~Resource< 中的 sync() 时完成的,意味着对象不再是 Image 类型,我们不能调用任何 Image 的方法。然而,其他仍然持有锁的线程将在完成后尝试调用 Image::unlock(),从而导致对 Resource::unlock() 的纯虚拟调用并中止程序。

明显的解决方案很简单:改为在 Image::~Image() 中调用 sync()

不幸的是,每当我从 ResourceImage 派生新类时,这种情况很容易再次发生。我在 Resource::~Resource() 中添加了一个 assert() 以检查 try_lock() 是否始终成功,但事实并非如此' 在我从 Image 派生时提供帮助。

所以我想知道是否有人知道更简单的方法来一劳永逸地防止这种竞争情况。谢谢。

最佳答案

作为一个想法,如果您可以使用一些工厂来创建从 Resource 派生的类的对象你可以让这个工厂返回 std::unique_ptr<DerivedResource> 而不是显式地创建它们使用自定义删除器调用 p_obj->sync()在实际删除 p_obj 的拥有实例之前.

关于c++ - 最多同步派生的析构函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44506905/

相关文章:

java - 在 Timer.Schedule() 中抛出空指针异常;

java - 当高吞吐量(3GB/s)文件系统可用时,如何在 Java 中使用多线程读取文件

c++ - 如何制作轻量级的加载-存储屏障

c++ - 显式调用时,析构函数被调用两次

c++ - 缺少析构函数声明

c++ - 为什么我的 io_service::run_one() 实现会导致无限期阻塞并触发错误 #125?

c++ - 内联函数的前向声明

c++ - std::vector 在重新分配时不调用析构函数

c++ - 解析包含顺序

c++ - 如何在 C++ 中查找程序的类名和标题?