在我编写或评论的大多数代码中,锁定是通过合成实现的,其中一个类拥有一个关键部分或互斥锁:
class MyClass
{
Mutex mMutex;
};
当可以通过多个线程访问可变成员时,我们通过RAII获取并释放锁定,如下所示:
void MyClass::Method()
{
Lock lock(mMutex);
// ...
}
今天我回顾了一些代码通过继承实现锁定的代码,如下所示:
class MyClass : public Mutex
{
// ...
};
锁定由类锁定“本身”执行:
void MyClass::Method()
{
Lock lock(this);
// ...
}
这种方法有什么优点或缺点吗?或者这只是一个风格问题?
答案 0 :(得分:6)
这几乎没有意义。 MyClass
是某种扩展Mutex
的同步对象吗?如果没有,那么继承几乎肯定是错误的选择,因为将MyClass
用作Mutex
没有意义(MyClass
与Mutex
的关系不是“是一种”关系。)
这也很危险:
MyClass x;
Lock lock(x);
x.Method(); // uh oh.
答案 1 :(得分:4)
私有继承可能对此更有意义,因为私有继承或多或少是实现组合的一种方式。但是,除非需要从Mutex
继承(如果Mutex
有需要访问的受保护成员),我认为使其成为成员的更标准的组合方法可能会导致更少混淆(就像人们想知道为什么使用继承而不是让Mutex
成为成员)。
公开继承可能有意义的一种情况是,您希望客户能够出于某种原因锁定该对象,然后他们可以将MyClass
视为Mutex
。这可能不是一个很好的设计选择,因为如果对象以意想不到的方式被锁定,你会为死锁提供更多机会。如果Mutex
保持私有(无论是通过继承还是通过标准组合),则类可以更确切地确定锁的使用方式。
如果引入此设计的人受到.NET的影响,任何对象都是“可锁定的”,我不会感到惊讶。请注意,在.NET中它曾经是lock(this)
的共同点,但这个习惯用法已经不受欢迎了,现在让一个特定的私有对象成员用来锁定更为正确。