【问题标题】:Locking via inheritance rather than composition通过继承而不是组合锁定
【发布时间】:2010-12-13 00:50:07
【问题描述】:

在我编写或查看的大多数代码中,锁定是通过组合实现的,其中类拥有一个临界区或互斥锁:

class MyClass
{
    Mutex mMutex;
};

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

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

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

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

并且锁定是由类锁定“本身”执行的:

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

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

【问题讨论】:

  • 您需要更加具体,尤其是在“继承互斥体”部分。是继承自接口还是真正的同步对象?
  • @YeenFei - 它继承自一个真实的(即具体的)同步对象。

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


【解决方案1】:

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

这也很危险:

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

【讨论】:

  • 请注意,在 Win32 世界中,一个线程可以多次获取锁,因此没有“哦哦”。这似乎是一种明智的锁定方法,但这可能是因为我已经习惯了。
  • @Michael:一些平台/线程库同时具有“互斥锁”和“递归互斥锁”,如果线程再次锁定互斥锁,它将与自身死锁。我不知道这是否是一种常见的方法。
【解决方案2】:

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

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

如果介绍此设计的人受到任何对象都是“可锁定”的 .NET 的影响,我不会感到惊讶。请注意,在 .NET 中,它曾经对 lock(this) 很常见,但该习惯用法已不受欢迎,现在认为使用特定的私有对象成员用于锁定更正确。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-21
    • 1970-01-01
    相关资源
    最近更新 更多