【问题标题】:How to define thread-local local static variables?如何定义线程局部静态变量?
【发布时间】:2011-11-28 05:29:50
【问题描述】:

如何定义不在不同线程之间共享的局部静态变量(在函数调用之间保持其值)?

我正在寻找 C 和 C++ 的答案

【问题讨论】:

  • 您使用的是什么操作系统? TLS 在 unixen 和 windows 之间是不可移植的。
  • C++11 引入了另一个存储持续时间,称为thread_local。尝试使用它。
  • @Nawaz:C++11 C11。在 C11 中,它是 _Thread_local,除非你还包括 <threads.h>(它在 thread_local 中添加了一个 #define,这在 C99 及更高版本中很常见)。

标签: c++ c multithreading static thread-safety


【解决方案1】:

在使用 Windows API 的 Windows 上:TlsAlloc()/TlsSetValue()/TlsGetValue()

在 Windows 上使用编译器内在函数:使用 _declspec(thread)

在 Linux 上(其他 POSIX ???):get_thread_area() 及相关

【讨论】:

  • 在 MSDN 上阅读后,Tls 函数正是我想要的。
【解决方案2】:

只需在函数中使用 static 和 __thread。

例子:

int test(void)
{
        static __thread a;

        return a++;
}

【讨论】:

  • @Ali:不,它是 GCC 和其他一些编译器提供的扩展。在 MSVC 上,我认为您使用 __declspec(thread) 代替。
  • __thread 适用于 linux、bsd、aix 以及 xl_c、gcc 和许多其他编译器。它可以在 Windows 上简单地 #defined 为 __declspec(thread)。
  • 它不适用于 macOS 上的 gcc 或 clang,因为它需要操作系统支持。
【解决方案3】:

当前的 C 标准没有线程或类似的模型,所以你无法得到答案。

POSIX 预见的实用程序是pthread_[gs]etspecific

下一个版本的C标准增加了线程,并且有了线程本地存储的概念

【讨论】:

    【解决方案4】:

    如果您可以访问 C++11,也可以使用 C++11 线程本地存储添加。

    【讨论】:

      【解决方案5】:

      您可以将自己的线程特定本地存储设置为每个线程 ID 的单例。像这样的:

      struct ThreadLocalStorage
      {
          ThreadLocalStorage()
          {
              // initialization here
          }
          int my_static_variable_1;
          // more variables
      };
      
      class StorageManager
      {
          std::map<int, ThreadLocalStorage *> m_storages;
      
          ~StorageManager()
          {   // storage cleanup
              std::map<int, ThreadLocalStorage *>::iterator it;
              for(it = m_storages.begin(); it != m_storages.end(); ++it)
                  delete it->second;
          }
      
          ThreadLocalStorage * getStorage()
          {
              int thread_id = GetThreadId();
              if(m_storages.find(thread_id) == m_storages.end())
              {
                  m_storages[thread_id] = new ThreadLocalStorage;
              }
      
              return m_storages[thread_id];
          }
      
      public:
          static ThreadLocalStorage * threadLocalStorage()
          {
              static StorageManager instance;
              return instance.getStorage();
          }
      };
      

      GetThreadId();是一个特定于平台的函数,用于确定调用者的线程 ID。像这样的:

      int GetThreadId()
      {
          int id;
      #ifdef linux
          id = (int)gettid();
      #else  // windows
          id = (int)GetCurrentThreadId();
      #endif
          return id;
      }
      

      现在,在线程函数中,您可以使用它的本地存储:

      void threadFunction(void*)
      {
        StorageManager::threadLocalStorage()->my_static_variable_1 = 5; //every thread will have
                                                                 // his own instance of local storage.
      }
      

      【讨论】:

      • 您还需要同步(例如读/写互斥锁)来保护m_storages 不被多个线程访问。
      • 不仅是 m_storages,还有 std::map 和本地的“静态 StorageManager 实例”;不是线程安全的。在本机代码中实现高效的单例并非易事,请参阅 Scott Meyers 和 Andrei Alexandrescu 的“C++ 和双重检查锁定的风险”。 erdani.com/publications/DDJ_Jul_Aug_2004_revised.pdf
      猜你喜欢
      • 2015-10-15
      • 2018-08-05
      • 1970-01-01
      • 1970-01-01
      • 2014-12-24
      • 2012-08-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多