web-dev-qa-db-ja.com

std :: atomic <>の使用方法

別のスレッドで使用したいクラスがあり、_std::atomic_を次のように使用できると思います。

_class A
{
    int x;

public:
    A()
    {
        x=0;
    }

    void Add()
    {
        x++;
    }

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

そして私のコードでは:

_  std::atomic<A> a;
_

そして別のスレッドで:

_  a.Add();
_

そして

_  a.Sub();
_

しかし、a.Add()が不明であるというエラーが表示されます。どうすれば解決できますか?

これを行うより良い方法はありますか?

これは例であり、クラスAへのアクセスがスレッドセーフであることを確認したいので、使用できないことに注意してください

_std::atomic<int> x;
_

_std::atomic_を使用してクラスをスレッドセーフにするにはどうすればよいですか?

28
mans

次のように、クラス全体ではなく、x属性をアトミックにする必要があります。

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

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

元のコードで発生するエラーは完全に正常です。std::atomic<A>::Addの特殊化を提供しない限り、std::atomic<A>メソッドはありません( here を参照)。

編集の参照class Aのテンプレート引数として使用して、std::atomicスレッドを魔法のように安全に作成することはできません。スレッドセーフにするには、その属性をアトミックにするか(上記で提案され、標準ライブラリで特殊化されている場合)、またはmutexを使用してリソースを自分でロックできます。 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 ...
  }

};
36
Unda

クラスメンバーxをアトミックとして宣言すれば、オブジェクトをアトミックとして宣言する必要はありません。

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

.演算子をオブジェクトで使用して、他のクラスのメンバー関数ではなく、クラスのメンバー関数を呼び出すことができます(明示的にコードを記述しない限り)。

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's hello member function
           // But the typeof(a) which is A does not have such a function
           // Hence it will be an error.
5
a_pradhan

上記の答えの問題は、少なくとも、質問のあいまいさ、そしておそらく、一般的なスレッド化された開発の誤acyであると思うことを説明していないことだと思います。

オブジェクトを「アトミック」にすることはできません。2つの関数の間隔(最初に「xを読み取る」、次に「xを書き込む」)が他の用途との競合を引き起こすためです。 「アトミック」オブジェクトが必要だと思われる場合は、APIとメンバー関数を慎重に設計して、オブジェクトの更新を開始およびコミットするために今すぐ公開する必要があります。

「アトミック」が意味するのが「オブジェクトが内部状態を破壊しない」ということだけであれば、std::atomic<>間に不変量がない単一の旧式データ型(aはbに依存しない)ですが、施行する必要のある依存ルールには何らかのロックが必要です。

1
Jon Watte