由于竞争条件,我遇到了因调用纯虚方法而崩溃的情况,其中其他线程在已经销毁的情况下仍在调用派生类的方法。这是它的要点:
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
派生时,这无济于事。
所以我想知道是否有人知道一种更加万无一失的方法来一劳永逸地防止这种竞争状态。感谢。
答案 0 :(得分:4)
作为一个想法,如果你可以使用一些工厂创建从Resource
派生的类的对象而不是显式创建它们,你可以使用自定义删除器使这个工厂返回std::unique_ptr<DerivedResource>
在实际删除p_obj->sync()
的所有实例之前p_obj
。