Подтвердить что ты не робот

Безопасен ли поток shared_ptr <XXX>?

У меня вопрос о 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>?

4b9b3361

Ответ 1

Из документа :

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

Любые другие одновременные обращения приводят к поведению undefined.

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

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

Ответ 2

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

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

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

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

Ответ 3

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

"...

Безопасность потоков

Функции С++ 0x-only: поддержка rvalue-ref/move, поддержка распределителя, конструктор псевдонимов, make_shared и allocate_shared. Кроме того, конструкторы, принимающие параметры auto_ptr, устарели в режиме С++ 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

Ответ 4

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

Ответ 5

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