Безопасно ли возвращать по значению shared_ptr, который защищен мьютексом? - PullRequest
4 голосов
/ 06 октября 2011

Вот пример кода:

class A {
  boost::mutex a_mutex;
  boost::shared_ptr<int> a;

  boost::shared_ptr<int> clone_a(void) {
    boost::lock_guard<boost::mutex> lock(a_mutex);
    return a;
  }
};

Предполагается, что вызов конструктора копирования boost::shared_ptr на A::a будет предшествовать вызову деструктора boost::lock_guard, несмотря на оптимизацию компилятора. Итак, безопасно ли звонить A::clone_a()?

Ответы [ 3 ]

5 голосов
/ 06 октября 2011

Если под "безопасным" вы подразумеваете, что не получите гонку данных на a, тогда да. Это именно так, как вы говорите.

Однако это не защитит дальнейший доступ к *a (или *clone_a()), как вы, вероятно, знаете. Я не уверен, почему метод называется «клонировать», поскольку он ничего не клонирует.

2 голосов
/ 07 октября 2011

Да, этот код безопасен. Если вы ссылаетесь на shread_ptr Thread-Safety , вы можете увидеть, что многопоточный доступ на запись к объектам shared_ptr с локальным потоком просто прекрасен.

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

Теперь, возможно, неправильный выбор clone_a в качестве имени функции. Вы не клонируете базовый объект, вы просто получаете копию shared_ptr. Поэтому я предполагаю, что вы намереваетесь разделить одно и то же базовое «int».

0 голосов
/ 06 октября 2011

Нет, если вы используете возвращаемое значение.Само возвращаемое значение является временным, время жизни которого выходит за пределы конца функции;оно будет уничтожено в конце полного выражения, которое вызывает A::clone_a.Поэтому, если вы напишите что-то вроде:

shared_ptr<int> newA = object->clone_a();

, формальная семантика будет для временного значения, возвращаемого object->clone_a(), которое будет скопировано в newA в контексте вызывающей стороны (и поэтому незащищеномьютекс).В этом конкретном случае вам может это сойти с рук из-за RVO, но это не обязательно так, и есть другие случаи, когда RVO не может вмешиваться.

Если все, что вас беспокоит, это копия указателя, я вполне уверен, что если вы установите правильные параметры компилятора (-D <i>somthing</i>), boost::shared_ptr будет вести себя атомарно.В этом случае вам вообще не нужен мьютекс.

...