Является ли boost shared_ptr <XXX>thread безопасным? - PullRequest
32 голосов
/ 28 марта 2009

У меня вопрос по поводу boost::shared_ptr<T>.

Есть много тем.

using namespace boost;

class CResource
{
  // xxxxxx
}

class CResourceBase
{
public:
   void SetResource(shared_ptr<CResource> res)
   {
     m_Res = res;
   }

   shared_ptr<CResource> GetResource()
   {
      return m_Res;
   }
private:
   shared_ptr<CResource> m_Res;
}

CResourceBase base;

//----------------------------------------------
// Thread_A:
    while (true)
    {
       //...
       shared_ptr<CResource> nowResource = base.GetResource();
       nowResource.doSomeThing();
       //...
    }

// Thread_B:
    shared_ptr<CResource> nowResource;
    base.SetResource(nowResource);
    //...

Q1

Если Thread_A все равно, nowResource является самым новым, будет ли эта часть кода иметь проблемы?

Я имею в виду, когда Thread_B не SetResource() полностью, Thread_A получает неправильную интеллектуальную точку на GetResource()?

Q2

Что означает потокобезопасность?

Если меня не волнует, является ли ресурс новейшим, произойдет ли сбой программы shared_ptr<CResource> nowResource при выпуске nowResource или проблема уничтожит shared_ptr<CResource>?

Ответы [ 5 ]

40 голосов
/ 28 марта 2009

boost::shared_ptr<> предлагает определенный уровень безопасности потока. Счетчик ссылок обрабатывается потокобезопасным способом (если вы не настроите boost для отключения поддержки потоков).

Таким образом, вы можете скопировать shared_ptr и ref_count будет поддерживаться корректно. То, что вы не можете сделать безопасно в нескольких потоках, - это изменить действительный экземпляр самого объекта shared_ptr из нескольких потоков (например, вызвать на нем reset() из нескольких потоков). Так что ваше использование небезопасно - вы изменяете фактический экземпляр shared_ptr в нескольких потоках - вам нужно иметь собственную защиту.

В моем коде shared_ptr обычно являются локальными или параметрами, передаваемыми по значению, поэтому проблем нет. Получая их из одного потока в другой, я обычно использую потокобезопасную очередь.

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

31 голосов
/ 28 марта 2009

С наддува Документация :

shared_ptr объекты предлагают то же самое уровень безопасности потока как встроенный типы. shared_ptr экземпляр может быть «чтение» (доступ только с использованием const операции) одновременно несколькими потоки. Разное shared_ptr экземпляры могут быть «записаны» (доступ с использованием изменяемых операций например operator= или сброс) одновременно несколькими потоками (даже когда эти экземпляры являются копиями, и использовать один и тот же счетчик ссылок внизу.)

Любой другой одновременный доступ приводит к неопределенному поведению.

Так что ваше использование небезопасно, поскольку оно использует одновременное чтение и запись m_res. Пример 3 в документации наддува также иллюстрирует это.

Вы должны использовать отдельный мьютекс , который защищает доступ к m_res в SetResource / GetResource.

3 голосов
/ 08 декабря 2010

Что ж, документация tr1 :: shared_ptr (которая основана на boost) рассказывает другую историю, которая подразумевает, что управление ресурсами является поточно-ориентированным, тогда как доступ к ресурсу - нет.

»...

Резьба безопасности

Возможности C ++ 0x: поддержка rvalue-ref / move, поддержка распределителя, конструктор псевдонимов, make_shared & allocate_shared. Кроме того, конструкторы, принимающие параметры auto_ptr, устарели в режиме C ++ 0x.

В разделе «Безопасность потоков» в документации Boost shared_ptr говорится, что «объекты shared_ptr обеспечивают тот же уровень безопасности потоков, что и встроенные типы». Реализация должна гарантировать, что одновременные обновления для отдельных экземпляров shared_ptr являются правильными, даже если эти экземпляры совместно используют счетчик ссылок, например

shared_ptr a (новый A); shared_ptr b (a);

// Тема 1 // Тема 2

a.reset (); b.reset ();

Динамически размещенный объект должен быть уничтожен ровно одним из потоков. Слабые ссылки делают вещи еще интереснее. Общее состояние, используемое для реализации shared_ptr, должно быть прозрачным для пользователя, а инварианты должны сохраняться всегда. Ключевыми элементами общего состояния являются сильные и слабые ссылки. Их обновления должны быть атомарными и видимыми для всех потоков, чтобы обеспечить правильную очистку управляемого ресурса (что, в конце концов, является задачей shared_ptr!). В многопроцессорных системах может потребоваться синхронизация памяти, чтобы обновления подсчета ссылок и уничтожение управляемого ресурса свободны от гонки.

... "

см http://gcc.gnu.org/onlinedocs/libstdc++/manual/memory.html#std.util.memory.shared_ptr

1 голос
/ 13 июня 2016

m_Res не является потокобезопасным, поскольку одновременно выполняет чтение / запись, вам нужна функция boost :: atomic_store / load для ее защиты.

//--- Example 3 ---
// thread A
p = p3; // reads p3, writes p
// thread B
p3.reset(); // writes p3; undefined, simultaneous read/write
0 голосов
/ 15 июня 2010

Добавьте, у вашего класса есть условие Cyclic-reference; shared_ptr<CResource> m_Res не может быть членом CResourceBase. Вы можете использовать weak_ptr вместо.

...