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

Как использовать std:: atomic <>

У меня есть класс, который я хочу использовать в разных потоках, и я думаю, что смогу использовать std:: atomic, например:

classs A
{
    int x;

public:
    A()
    {
        x=0;
    }

    void Add()
    {
        x++;
    }

    void Sub()
    {
        x--;
    }     
};

и в моем коде:

  std::atomic<A> a;

и в другом потоке:

  a.Add();

и

  a.Sub();

но когда я получаю ошибку, что a.Add() неизвестно. Как я могу достичь этого?

Есть ли лучший способ сделать это?

Изменить 1

Обратите внимание, что это примерный пример, и я хочу, чтобы доступ к классу A был потокобезопасным, поэтому я не могу использовать

std::atomic<int> x;

Как я могу создать потоки классов с помощью std:: atomic?

4b9b3361

Ответ 1

Вам нужно сделать атрибут x атомарным, а не всем вашим классом, следующим образом:

class A
{
    std::atomic<int> x;

    public:
      A() {
        x=0;
      }
      void Add() {
        x++;
      }
      void Sub() {
        x--;
      }     
};

Ошибка, которую вы получаете в исходном коде, абсолютно нормальная: нет метода std::atomic<A>::Add (см. здесь), если вы не предоставите специализацию для std::atomic<A>.

Ссылаясь на ваше редактирование: вы не можете магически сделать поток class A безопасным, используя его как аргумент шаблона std::atomic. Чтобы сделать его потокобезопасным, вы можете сделать его атрибуты атомарными (как было предложено выше, и при условии, что стандартная библиотека дает для него специализацию) или использовать мьютексы для блокировки ваших ресурсов самостоятельно. См. Заголовок mutex. Например:

class   A
{
  std::atomic<int>      x;
  std::vector<int>      v;
  std::mutex            mtx;

  void  Add() {
    x++;
  }
  void  Sub() {
    x--;
  }

  /* Example method to protect a vector */
  void  complexMethod() {
    mtx.lock();

    // Do whatever complex operation you need here
    //  - access element
    //  - erase element
    //  - etc ...

    mtx.unlock();
  }

  /*
  ** Another example using std::lock_guard, as suggested in comments
  ** if you don't need to manually manipulate the mutex
  */
  void  complexMethod2() {
    std::lock_guard<std::mutex> guard(mtx);

    // access, erase, add elements ...
  }

};

Ответ 2

Объявить член класса x как атомный, тогда вам не нужно объявлять объект как атомный

class A
{  
   std::atomic<int> x;
}

Ответ 3

Оператор . может использоваться для объекта, чтобы вызвать его функцию-член класса, а не какую-либо другую функцию-член класса (если вы явно не пишете код таким образом).

std::atomic<A> a ;
a.Add(); // Here, a does not know what Add() is (a member function of the type parameter)
         // It tries to call Add() method of its own class i.e. std::atomic
         // But std::atomic has no method names Add or Sub

Как следует из ответа @ivanw, сделайте std::atomic<int> членом своего класса, а затем используйте его.

Вот еще один пример:

template <typename T> class A
{};

class B { public: void hello() { std::cout << "HELLO!!!"; } };

A<B> a ;
a.hello(); // This statement means that call a hello member function
           // But the typeof(a) which is A does not have such a function
           // Hence it will be an error.

Ответ 4

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

Вы не можете сделать объект "атомарным", потому что интервал между двумя функциями (сначала "read x", а затем "write x" ) вызовет гонку с другими видами использования. Если вы считаете, что вам нужен "атомный" объект, тогда вам нужно тщательно разработать API и функции-члены, чтобы выставлять сейчас, чтобы начинать и фиксировать обновления для объекта.

Если все, что вы имеете в виду под "атомарным", это "объект не повреждает его внутреннее состояние", тогда вы можете достичь этого через std::atomic<> для одиночных типов данных простого старого типа, которые не имеют инварианта между ними (a doesn 't зависит от b), но вам нужна какая-либо блокировка для любых зависимых правил, которые вам необходимо выполнить.