每个线程的局部静态变量

Bre*_*men 15 c++ static multithreading c++11

假设我有一个类,在初始化之后创建一个线程并在其中运行一个方法,在其中声明一个静态变量:

void method()
{
     static int var = 0;
     var++;
}
Run Code Online (Sandbox Code Playgroud)

如果我创建了更多类的对象,例如3,那么该方法将在3个不同的线程中被调用3次.之后var将等于3.如何完成功能,其中每个线程都有自己的静态var,独立于其他线程.我将非常感谢所有的帮助.

Pum*_*kko 34

您可以使用thread_local表示该对象具有线程存储持续时间的关键字.你可以像这样使用它:

static thread_local int V;
Run Code Online (Sandbox Code Playgroud)

如果需要有关存储类说明符的更多信息,可以查看CppReference.

  • 而如果你的编译器不支持它,看看Boost的[thread_local_storage(http://www.boost.org/doc/libs/1_58_0/doc/html/thread/thread_local_storage.html),这确实基本上是相同的,但作为一个图书馆. (2认同)

Tar*_*ama 13

这就是thread_local存储类说明符的用途:

void method()
{
     thread_local int var = 0;
     var++;
}
Run Code Online (Sandbox Code Playgroud)

这意味着每个线程都有自己的版本var,它将在第一次运行该函数时初始化,并在线程退出时销毁.

  • 我认为如果您回顾(或至少链接到)使用线程本地存储可能对性能产生的影响,这个答案会更好。 (2认同)

Rei*_*ica 7

你在评论中说:

我确实想要一个特定于每个类实例的变量

这正是实例变量(也就是每个实例成员).

static成员和函数局部变量并不特定于每个类的实例!它们要么是完全全局的(每个可执行文件一个实例),要么是每个线程,如果你使用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; } };
Run Code Online (Sandbox Code Playgroud)

如果需要,可以通过在变量名称中包含方法名称来表明您的意图:

class C {
  int foo_var;
  C() : foo_var(0) {}
  void foo() { ... }
};
Run Code Online (Sandbox Code Playgroud)

最后,如果你可以输入更多内容,可以使用成员包装器来强制执行它所使用的范围:

#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;
}
Run Code Online (Sandbox Code Playgroud)