Совместное использование члена данных с внешним миром в защитной форме

StackOverflow https://stackoverflow.com/questions/4449915

Вопрос

Я был бы очень признателен по этому вопросу по этому вопросу.

например

class Foo
{
    TData data;
public:
    TData *getData() { return &data; } // How can we do this in a thread safe manner ?
};

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

class locked_object : boost::noncopyable
{
    T *object;
    TLockable *lock;
    bool locked;

public:
    locked_object(T *_object, TLockable *_lock) : object(_object), lock(_lock), locked(true)
    {
        lock->lock();
    }

    ~locked_object()
    {
        lock->unlock();
    }

    T *get()
    {
        _ASSERT(locked);
        if (!locked)
            throw new std::exception("Synchronization error ! Object lock is already released !");
        return this->tobject;
    }


    void unlock()
    {
        locked = false;

        lock->unlock();
    }

    T *operator ->() const
    {   
        _ASSERT(locked);
        if (!locked)
            throw new std::exception("Synchronization error ! Object lock is already released !");

        return this->tobject; 
    }

    operator T *() const
    {
        _ASSERT(locked);
        if (!locked)
            throw new std::exception("Synchronization error ! Object lock is already released !");

        return this->tobject;
    }
};

Спасибо за любые комментарии и мнения заранее.

Фатих

Это было полезно?

Решение

Вы когда -нибудь слышали о Закон Деметера ?

Есть аналогичный совет (от Саттера, я думаю): Не делитесь ссылками на ваши внутренние

Оба предназначены для избежания связь, Потому что, поделившись ссылкой на ваш внутренний, это означает, что ваш публичный интерфейс утечет подробную информацию о реализации.

Теперь, когда это сказано, ваш интерфейс не работает.

Проблема в том, что вы блокируете прокси, а не объект: я все еще могу получить доступ через несколько путей:

  • из Foo, не требуется мутекс -> oups?
  • от двух разных locked_object -> Это не кажется намеренным ...

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

Другие советы

Ваш дизайн наносит на пользователя на ONUS, чтобы убедиться, что объект заблокирован и разблокирован в правильное время. И даже если ваш заблокированный объект проверяет ошибки, он не покрывает все основания (например, забыть о том, чтобы отпустить объект, когда закончите с ним)

Итак, допустим, у вас есть небезопасный объект TData. Анкет Вы оберните это в Foo но вместо Foo возвращая указатель на TData, переосмыслить все публичные методы в TData в Foo но используя замки и разблокирует.

Это очень похоже на сухой шаблон, кроме вашего интерфейса, добавляет блокировки перед вызовом реализации. Таким образом, пользователь просто знает, что объект является безопасным потоком, и ему не нужно беспокоиться о синхронизации.

Это основная проблема мультиподбота, вы не можете требовать, чтобы клиент-код использовал ваш объект безопасным образом. Вы не можете сделать что -либо, чтобы помочь клиентскому коду попасть в яму успеха, он должен позаботиться о блокировке самостоятельно. Внесение ответственности за то, чтобы ваш код работал над человеком, который меньше всего может сделать это правильно.

Вы можете сделать это проще, вернув копия объекта от вашего доклада. Это безопасно, там будет только одна копия, принадлежащая одной потоке. Вы, вероятно, должны сделать тип этой копии неизбежным для повторного применения, что изменение объекта вряд ли имеет желаемый результат. Неразрешимый побочный эффект, который может плохо кусаться, заключается в том, что эта копия по определению устарела. Это пластырь, которые могут принести больше вреда, чем пользы.

Документируйте начинку из метода, чтобы клиент -программист знал, что делать.

Это не особенно безопасно. Ничто не мешает пользователю вывести вещи в порядке:

locked_object<T> o(...);
T* t = o.get();
o.unlock();
t->foo(); // Bad!

Конечно, легко понять, почему вышеупомянутый код плох, но реальный код гораздо сложнее, и есть много способов, которыми указатели могут зависать после выпуска блокировки, которые гораздо сложнее определить.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top