web-dev-qa-db-ja.com

各スレッドのローカル静的変数

初期化後にスレッドを作成し、その中でメソッドを実行するクラスがあり、その中で静的変数を宣言するとします。

void method()
{
     static int var = 0;
     var++;
}

クラスのオブジェクトをさらに作成すると(たとえば3)、メソッドは3つの異なるスレッドで3回呼び出されます。その後、varは3になります。機能を実現する方法。各スレッドには、他のスレッドから独立した独自の静的varがあります。私はすべての助けをいただければ幸いです。

15

thread_localキーワードを使用して、オブジェクトにスレッドの保存期間があることを示すことができます。あなたはそれをそのように使うことができます:

static thread_local int V;

ストレージクラス指定子の詳細が必要な場合は、 CppReference を確認できます。

34
Pumkko

これがthread_localストレージクラス指定子は、

void method()
{
     thread_local int var = 0;
     var++;
}

これは、各スレッドが独自のバージョンのvarを持ち、その関数を最初に実行したときに初期化され、スレッドの終了時に破棄されることを意味します。

13
TartanLlama

あなたはコメントで言った:

クラスの各インスタンスに固有の変数が必要です

これがまさにインスタンス変数です(インスタンスごとのメンバーとも呼ばれます)。

staticメンバーと関数のローカル変数はnotクラスの各インスタンスに固有です!それらは完全にグローバル(実行可能ファイル全体ごとに1つのインスタンス)であるか、C++ 11を使用して宣言する場合はスレッドごとですthread_local

絶対にメンバー変数が必要です。これが、変数がクラスの各インスタンスに固有であることを保証する唯一の方法です。

クラスの各インスタンスごとに専用スレッドを作成すると主張するかもしれません。まず第一に、あなたがそうするべきではない可能性が高いです。次に、気が変わってクラスごとのスレッドの作成を停止し、代わりにスレッドプールを使用すると、コードはすぐに壊れてしまいます。

したがって、適切で簡単なことは、インスタンス変数として(クラス変数ではなく)持つことです。

// OK - instance variable
class C { int var; };

// WRONG - class variable and lookalikes
class C { static int var; };
class C { void foo() { static int var; } };

// WRONG - thread variable, but **not** instance variable
class C { static thread_local int var; };
class C { void foo() { static thread_local int var; } };

必要に応じて、変数名にメソッドの名前を含めることで、意図を示すことができます。

class C {
  int foo_var;
  C() : foo_var(0) {}
  void foo() { ... }
};

最後に、もう少し入力しても問題がない場合は、メンバーラッパーを使用して、使用されているスコープを適用できます。

#include <utility>
#include <cassert>

template <typename T, typename Member, Member member>
class ScopedMember {
   T data;
public:
   explicit ScopedMember(const T & d) : data(d) {}
   explicit ScopedMember(T && d) : data(std::move(d)) {}
   ScopedMember() {}
   template <Member m, void(*)(char[member == m ? 1 : -1]) = (void(*)(char[1]))0>
   T & use() { return data; }
   template <Member m, void(*)(char[member == m ? 1 : -1]) = (void(*)(char[1]))0>
   const T & use() const { return data; }
};

class C {
public:
   C() : m_foo(-1) {}
   void granted() {
      auto & foo = m_foo.use<&C::granted>();
      foo = 5;
      assert(m_foo.use<&C::granted>() == 5);
   }
   void rejected() {
#if 0
      // Won't compile
      auto & foo = m_foo.use<&C::rejected>();
#endif
   }
private:
   ScopedMember<int, void(C::*)(), &C::granted> m_foo;
};

int main()
{
   C().granted();
   return 0;
}
7
Kuba Ober