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

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()sync() 中的 Resource::~Resource 时完成,这意味着对象不再属于 Image 类型,我们无法调用 Image 的任何方法。然而,其他仍然持有锁的线程会在完成后尝试调用 Image::unlock(),从而导致对 Resource::unlock() 的纯虚拟调用并中止程序。

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

不幸的是,每当我从 Resource 或从 Image 派生一个新类时,这种情况很容易再次发生。我在 assert() 中添加了一个 Resource::~Resource() 来检查 try_lock() 是否总是成功,但是当我从 Image 派生时这没有帮助。

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

最佳答案

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

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

10-11 22:51
查看更多