5

我正在编写一个 C++11 类 Foo,我想为每个实例提供其自己的 Bar 类型的线程本地存储。也就是说,我希望为每个线程每个 Foo 实例分配一个 Bar。

如果我使用 pthreads,Foo 将有一个 pthread_key_t 类型的非静态成员,Foo 的构造函数将使用 pthread_key_create() 对其进行初始化,而 Foo 的析构函数将使用 pthread_key_delete() 释放。或者,如果我只为 Microsoft Windows 编写代码,我可以用 TlsAlloc() 和 TlsFree() 做类似的事情。或者,如果我使用的是 Boost.Thread,Foo 将有一个 boost::thread_specific_ptr 类型的非静态成员。

然而,实际上,我正在尝试编写可移植的 C++11。C++11 的thread_local关键字不适用于非静态数据成员。因此,如果您希望每个线程有一个 Bar,但如果您希望每个 Foo 的每个线程有一个 Bar,则不是这样。

据我所知,我需要定义一个从 Foos 到 Bars 的线程本地映射,然后处理如何在 Foo 被销毁时进行适当清理的问题。但在我开始之前,我在这里发帖希望有人会阻止我并说“有一个更简单的方法”。

(顺便说一句,我不使用 pthread_key_create() 或 boost::thread_specific_ptr 的原因是,如果我理解正确,他们假设所有线程都将分别使用 pthreads 或 Boost.Thread 生成。我不想关于我的代码的用户将如何产生线程的任何假设。)

4

1 回答 1

2

您想Foo包含一个thread_local类型为 的变量Bar。如前所述,由于thread_local不能应用于数据成员,因此我们必须做一些更间接的事情。底层行为将是对于Bar的每个实例都存在N 个实例Foo,其中 N 是存在的线程数。

这是一种效率较低的方法。使用更多代码,它可以变得更快。基本上,每个 Foo 都将包含一个 TLS 映射。

#include <unordered_map>

class Bar { ... };

class Foo {
private:
  static thread_local std::unordered_map<Foo*, Bar> tls;
public:    
  // All internal member functions must use this too.
  Bar *get_bar() {
    auto I = tls.find(this);
    if (I != tls.end())
      return &I->second;
    auto II = tls.emplace(this, Bar()); // Could use std::piecewise_construct here...
    return &II->second.second;
  }
};
于 2014-03-22T21:18:53.363 回答