Защита Mutex для ресурсов Singleton в многопоточной среде - PullRequest
0 голосов
/ 22 июля 2010

У меня есть сервер, прослушивающий порт для запроса.Когда приходит запрос, он отправляется в одноэлементный класс Singleton.Этот класс Singleton имеет структуру данных RootData.<pre> class Singleton { void process(); void refresh();</p> <p>private: RootData mRootData; }

В классе есть две функции: process: работать с mRootData для некоторой обработки и refresh: периодически вызываться из другого потока, чтобы обновить mRootData с последними изменениями.из базы данных.

Mutex требует доступа к mRootData.

У меня есть следующие вопросы:

1] Если класс одиночный и mRootData находится внутри этого класса, действительно ли необходим Mutex gaurd?Я знаю, что это необходимо для конфликта между обновлением / процессом.Но с сервера я думаю, что в любой момент времени будет происходить только один вызов процесса (потому что класс - Singleton). Пожалуйста, исправьте меня, если мое понимание неверно.

2] Должен ли я защищать i)структура данных ИЛИ ii) функция доступа к структуре данных.Например,

    i) <code> const RootData& GetRootData()
        {
               ACE_Read_Guard guard(m_oMutexReadWriteLock);
               return mRootData;
               // Mutex is released when this function returns
        }
        // Similarly Write lock for SetRootData()
    </code> 
    ii) <code>void process()
        {
              ACE_Read_Guard guard(m_oMutexReadWriteLock);
              // use mRootData and do processing
              // GetRootData() and SetRootData() wont be mutex protected.
              // Mutex is released when this function returns
        }
</code> 

3] Если ответ на вопрос выше: i) я должен вернуться по ссылке или по объекту?Пожалуйста, объясните в любом случае.

Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 22 июля 2010

1] Если класс является одноэлементным, а mRootData находится внутри этого класса, действительно ли необходим Mutex gaurd?

Да, поскольку один поток может вызывать process(), а другой - refresh().

2] Должен ли я защищать i) структуру данных ИЛИ ii) функцию доступа к структуре данных.

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

Обновление : если GetRootData и SetRootData также являются публичными функциями, нет особого смысла защищать их мьютексами в их текущем виде. Проблема заключается в том, что вы публикуете ссылку на общие данные, после чего они полностью не контролируют, что и когда могут делать с ними вызывающие. 100 абонентов из 100 различных потоков могут сохранить ссылку на mRootData и принять решение об ее изменении одновременно! Аналогично, после вызова SetRootData вызывающая сторона может сохранить ссылку на корневые данные и получить к ней доступ в любое время, даже если вы этого не заметите (за исключением случаев повреждения данных или тупика ...).

У вас есть следующие варианты (кроме молитвы о том, чтобы клиенты были милыми и не делали гадости вашему бедному синглтону; -)

  • создать глубокую копию mRootData как в получателе, так и в установщике. Это позволяет хранить данные в единственном экземпляре, где они могут быть защищены с помощью блокировок. Вызывающие OTOH GetRootData получают снимок данных, и последующие изменения не видны им - это может быть или не быть приемлемым для вас.
  • переписать RootData, чтобы сделать его потокобезопасным, тогда синглтону не нужно больше заботиться о безопасности потока (в его текущей настройке - если у него есть другие элементы данных, картина может отличаться).

Обновление2 :

  • или вообще удалите геттер и сеттер (возможно, вместе с перемещением методов обработки данных из других классов в синглтон, где они могут быть должным образом защищены мьютексами). Это было бы самым простым и безопасным, если вам абсолютно не нужны другие стороны для прямого доступа к mRootData.
0 голосов
/ 22 июля 2010

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

2.) Каждый раз, когда вы используете значение, вы должны защищать его мьютексом.

Однако вы не упоминаете GetRootData и SetRootData в объявлении класса выше.Являются ли они частными (используются только внутри класса для доступа к данным) или общедоступными (чтобы позволить другому коду получать прямой доступ к данным)?

Если вам необходимо предоставить внешний доступ к данным, сделав GetRootData ()Функция public, тогда вам нужно будет вернуть копию, или ваши абоненты могут сохранить ссылку и манипулировать данными после снятия блокировки.Конечно, тогда изменения, внесенные в данные, не будут отражены в синглтоне, что может оказаться не тем, что вы хотите.

...