我遇到了一个令我很困扰的问题。看来我已经找到了一种很容易解决的情况,但是如果 a) 我在编程时注意力不集中,或者 b) 其他人开始实现我的接口(interface)并且不知道如何处理,那可能会导致问题这种情况。
这是我的基本设置:
我有一个抽象类,用作多种数据类型的通用接口(interface)。我采用了非虚拟公共(public)接口(interface)范例(Sutter,2001)以及范围锁定来提供一些线程安全性。一个示例接口(interface)类看起来像这样(我省略了有关作用域锁定和互斥实现的详细信息,因为我认为它们不相关):
class Foo
{
public:
A( )
{
ScopedLock lock( mutex );
aImp( );
}
B( )
{
ScopedLock lock( mutex );
bImp( );
}
protected:
aImp( ) = 0;
bImp( ) = 0;
}
然后由用户来实现 aImp 和 bImp,这就是问题所在。如果 aImp 执行一些使用 bImp 的操作,则执行此操作非常容易(并且在某种意义上几乎合乎逻辑):
class Bar
{
protected:
aImp( )
{
...
B( );
...
}
bImp( )
{
...
}
}
僵局。当然,解决这个问题的简单方法是始终调用 protected 虚函数而不是它们的公共(public)变体(在上面的代码片段中将 B() 替换为 bImp())。但如果我犯了一个错误,我上吊似乎仍然很容易,或者更糟的是允许其他人上吊。
有没有人有办法阻止抽象类的实现者在编译时调用那些公共(public)函数,或者以其他方式帮助避免死锁解决方案?
只是为了好玩,一些互斥量允许操作以避免死锁问题。例如,如果我使用 Windows 函数 EnterCriticalSection 和 LeaveCriticalSection 实现它,就没有问题。但我宁愿避免平台特定的功能。我目前在我的作用域锁实现中使用 boost::mutex 和 boost::shared_mutex,据我所知,它并没有试图避免死锁(我认为我几乎更喜欢)。
最佳答案
使用私有(private)继承可能会解决您的问题:
class Foo
{
public:
void A( )
{
ScopedLock lock( mutex );
aImp( );
}
void B( )
{
ScopedLock lock( mutex );
bImp( );
}
protected:
virtual void aImp( ) = 0;
virtual void bImp( ) = 0;
};
class FooMiddle : private Foo
{
public:
using Foo::aImp;
using Foo::bImp;
};
class Bar : public FooMiddle
{
virtual void aImpl ()
{
bImp ();
B (); // Compile error - B is private
}
};
私有(private)地从 Foo 派生,然后使用 FooMiddle 确保 Bar 无法访问 A 或 B。但是,bar 仍然能够覆盖 aImp 和 bImp,并且 FooMiddle 中的 using 声明意味着它们仍然可以被调用来自酒吧。
或者,有帮助但不能解决问题的选项是使用 Pimpl 模式。你最终会得到如下结果:
class FooImpl
{
public:
virtual void aImp( ) = 0;
virtual void bImp( ) = 0;
};
class Foo
{
public:
void A( )
{
ScopedLock lock( mutex );
m_impl->aImp( );
}
void B( )
{
ScopedLock lock( mutex );
m_impl->bImp( );
}
private:
FooImpl * m_impl;
}
好处是在从 FooImpl 派生的类中,它们不再有“Foo”对象,因此不能轻易调用“A”或“B”。
关于c++ - 在 C++ 中使用非虚拟公共(public)接口(interface)和作用域锁避免死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/834865/