我在调用纯虚方法时遇到了崩溃,这是由于竞争条件导致其他线程仍在调用已销毁的派生类的方法。这是它的要点:
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()
。
不幸的是,每当我从 Resource
或 Image
派生新类时,这种情况很容易再次发生。我在 Resource::~Resource()
中添加了一个 assert()
以检查 try_lock()
是否始终成功,但事实并非如此' 在我从 Image
派生时提供帮助。
所以我想知道是否有人知道更简单的方法来一劳永逸地防止这种竞争情况。谢谢。
最佳答案
作为一个想法,如果您可以使用一些工厂来创建从 Resource
派生的类的对象你可以让这个工厂返回 std::unique_ptr<DerivedResource>
而不是显式地创建它们使用自定义删除器调用 p_obj->sync()
在实际删除 p_obj
的拥有实例之前.
关于c++ - 最多同步派生的析构函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44506905/