Нужно ли использовать std::atomic_ при наличии одного потока чтения и одного потока записи

Я хочу использовать std::shared_ptr в сценарии чтения/записи. Один поток постоянно получает новую информацию и хранит интеллектуальный указатель на последние данные. Когда приходит время запустить мой медленный расчет, я беру интеллектуальный указатель на все данные, чтобы убедиться, что я смотрю на согласованные данные. В приведенном ниже примере, когда я использую a, а затем b, я знаю, что они принадлежат друг другу.

Я не уверен, следует ли мне использовать здесь atomic_load и atomic_store? Мне все равно, на какую версию Foo я смотрю, пока она непротиворечива и действительна.

Итак, должен ли я использовать atomic здесь для своих интеллектуальных указателей, чтобы этот код работал из двух разных потоков?

Спасибо,

Павел

#include <iostream>
#include <memory>


class Foo{
public:
    int a;
    int b;
};

class MyClass{
public:
  std::shared_ptr <Foo> lastValue;
  void realTimeUpdate (Foo* latest) { //takes ownership of Foo
      lastValue=std::shared_ptr <Foo> (latest); //Is this OK to do without using std::atomic_?
  };

  void doSlowCalcFromAnotherThread () {
      //take a reference to all input data
      std::shared_ptr <Foo> stableValue=lastValue; //Is this OK to do without using std::atomic_
      //display a and b guaranteed that they come from the same message
      std::cout<<"a: "<<stableValue->a<<std::endl;
      std::cout<<"b: "<<stableValue->b<<std::endl;
  };
};

person Paul Beerkens    schedule 04.04.2016    source источник
comment
Вы, вероятно, должны использовать std::mutex для защиты доступа к указателю и называть это днем. Назначение std::shared_ptr не является атомарным.   -  person Alexandre C.    schedule 05.04.2016


Ответы (3)


  1. shared_ptr::operator= по умолчанию не является атомарным.
  2. shared_ptr не является TriviallyCopyable, поэтому он не может быть параметром шаблона для std::atomic.

Поэтому вам нужно синхронизировать их каким-то другим способом, например. через std::mutex.

person bipll    schedule 04.04.2016

Да, вы должны использовать перегруженные std::atomic_load() и std::atomic_store() в заголовке memory для std::shared_ptr аргументов. В противном случае у вас будет гонка данных в коде. (Я предполагаю, что у вас есть компилятор, совместимый с С++ 11, в соответствии с тегами вопроса.)

person Daniel Langr    schedule 05.04.2016
comment
Спасибо. К сожалению, похоже, что gcc 4.9.2 не реализует std::atomic_load и не хранит std::shared_ptr, поэтому мне приходится придерживаться мьютекса. С++ 17 может включать std::atomic_shared_ptr, который должен работать в этих случаях, но это произойдет через некоторое время, прежде чем он будет доступен. - person Paul Beerkens; 05.04.2016

Да, любое взаимодействие между двумя потоками должно быть каким-то образом защищено. Проблема в этом случае заключается в том, что std::shared_ptr<>::operator= не гарантируется атомарностью и, следовательно, может вызывать неопределенное поведение, если к нему обращаются оба потока.

person kmdreko    schedule 04.04.2016
comment
Я надеялся использовать что-то вроде en.cppreference.com/w/cpp/memory /shared_ptr/атомный - person Paul Beerkens; 05.04.2016
comment
Если у вас есть компилятор С++ 11, вы можете это сделать! И все будет хорошо - person kmdreko; 05.04.2016