每个线程的局部静态变量

Local static variables for each thread

本文关键字:静态 变量 局部 线程      更新时间:2023-10-16

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

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

如果我创建了更多的类对象,例如3,那么该方法将在3个不同的线程中被调用3次。之后,var等于3。如何实现该功能,其中每个线程都有自己独立于其他线程的静态var

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

static thread_local int V;

如果您想了解更多关于存储类说明符的信息,可以查看CppReference

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

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

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

你在评论中说:

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

这就是实例变量(也就是每个实例的成员)。

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; } };

如果你愿意,你可以通过在变量name中包含方法名来表明你的意图:

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;
}

如果你想让一个变量在不同的线程之间不同,那么这个变量不应该是静态的。它失去了静态变量的意义,根据定义,静态变量是:

    由该类的所有对象共享。
  1. 不需要类实例(对象)来访问。

你问的问题不是一个"编码问题",而是一个架构问题。我不知道你在开发什么样的系统/应用,也许你需要用不同的方法来解决你的问题。

问自己这些问题:

    为什么我需要线程?
  • 为什么我需要这个变量是静态的?
  • 我需要在线程之间共享哪些信息,不想共享哪些信息?

如果你更具体,也许我可以给你一个更具体的答案/方法。