Блокировка с помощью наследования, а не композиции - PullRequest
3 голосов
/ 13 декабря 2010

В большинстве кодов, которые я написал или рассмотрел, блокировка достигается посредством композиции, где классу принадлежит критическая секция или мьютекс:

class MyClass
{
    Mutex mMutex;
};

и когда к изменяемым элементам потенциально можно получить доступ через несколько потоков, мы получаем и снимаем блокировку через RAII следующим образом:

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

Сегодня я рассмотрел некоторый код, в котором код реализовывал блокировку посредством наследования, например:

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

А блокировка выполняется классом блокировки "само":

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

Есть ли какие-либо преимущества или недостатки этого подхода? Или это просто вопрос стиля?

Ответы [ 2 ]

6 голосов
/ 13 декабря 2010

Это почти никогда не имеет смысла. MyClass это какой-то объект синхронизации, который расширяет Mutex? Если нет, то наследование почти наверняка является неправильным выбором, потому что не имеет смысла использовать MyClass как Mutex (отношение MyClass к Mutex не является отношением "есть").

Это также опасно:

MyClass x;
Lock lock(x);
x.Method();   // uh oh.
4 голосов
/ 13 декабря 2010

Частное наследование может иметь немного больше смысла для этого, поскольку частное наследование является более или менее способом реализации композиции. однако, если нет необходимости наследовать от Mutex (например, если Mutex имеет защищенных членов, к которым необходимо получить доступ), я думаю, что более стандартный композиционный подход, делающий его членом, вероятно, вызовет меньше путаницы (как у людей интересно, почему наследование было использовано вместо Mutex члена).

Одна ситуация, в которой может иметь смысл публичное наследование, - это когда вы хотите, чтобы клиенты могли по какой-то причине иметь возможность блокировать этот объект, тогда они могут просто трактовать MyClass как Mutex. Это может быть не лучшим выбором для дизайна, поскольку вы открываете больше возможностей для тупиковой ситуации, если объект заблокирован непредвиденными способами. Если Mutex остается закрытым (по наследованию или по стандартной композиции), класс может быть более уверен в том, как именно используется блокировка.

Я бы не удивился, если бы человек, который представил этот дизайн, находился под влиянием .NET, где любой объект «блокируется». Обратите внимание, что в .NET раньше он был общим для lock(this), но эта идиома впала в немилость, и теперь считается более правильным иметь конкретный член частного объекта, который будет использоваться для блокировки.

...