通过继承而不是组合来锁定

时间:2010-12-13 00:50:08

标签: c++ inheritance locking mutex critical-section

在我编写或评论的大多数代码中,锁定是通过合成实现的,其中一个类拥有一个关键部分或互斥锁:

class MyClass
{
    Mutex mMutex;
};

当可以通过多个线程访问可变成员时,我们通过RAII获取并释放锁定,如下所示:

void MyClass::Method()
{
    Lock lock(mMutex);
    // ...
}

今天我回顾了一些代码通过继承实现锁定的代码,如下所示:

class MyClass : public Mutex
{
    // ...
};

锁定由类锁定“本身”执行:

void MyClass::Method()
{
    Lock lock(this);
    // ...
}

这种方法有什么优点或缺点吗?或者这只是一个风格问题?

2 个答案:

答案 0 :(得分:6)

这几乎没有意义。 MyClass是某种扩展Mutex的同步对象吗?如果没有,那么继承几乎肯定是错误的选择,因为将MyClass用作Mutex没有意义(MyClassMutex的关系不是“是一种”关系。)

这也很危险:

MyClass x;
Lock lock(x);
x.Method();   // uh oh.

答案 1 :(得分:4)

私有继承可能对此更有意义,因为私有继承或多或少是实现组合的一种方式。但是,除非需要从Mutex继承(如果Mutex有需要访问的受保护成员),我认为使其成为成员的更标准的组合方法可能会导致更少混淆(就像人们想知道为什么使用继承而不是让Mutex成为成员)。

公开继承可能有意义的一种情况是,您希望客户能够出于某种原因锁定该对象,然后他们可以将MyClass视为Mutex。这可能不是一个很好的设计选择,因为如果对象以意想不到的方式被锁定,你会为死锁提供更多机会。如果Mutex保持私有(无论是通过继承还是通过标准组合),则类可以更确切地确定锁的使用方式。

如果引入此设计的人受到.NET的影响,任何对象都是“可锁定的”,我不会感到惊讶。请注意,在.NET中它曾经是lock(this)的共同点,但这个习惯用法已经不受欢迎了,现在让一个特定的私有对象成员用来锁定更为正确。