【问题标题】:Simulate thread local variables模拟线程局部变量
【发布时间】:2013-10-24 11:00:40
【问题描述】:

我想为非静态成员模拟线程局部变量,像这样:

template< typename T, unsigned int tNumThread >
class ThreadLocal
{
private:

protected:
    T mData[tNumThread];

    unsigned int _getThreadIndex()
    {
        return ...; // i have a threadpool and each thread has an index from 0 to n
    }

public:
    ThreadLocal() {};
    ~ThreadLocal() {};

    T& operator ->()
    {
        return mData[_getThreadIndex()];
    }
    ...
};

但问题是线程数将在运行时确定,我必须从堆中分配mData

我想知道有没有什么办法不使用堆分配而使用像上面这样的常规数组?

【问题讨论】:

  • 编译器通常会提供扩展语法来执行此操作。您需要提及您的编译器名称和版本。
  • @HansPassant 如果我没记错的话,在 VS 中我们有 _declspec(thread) 和 c++11 中的 threadlocal 但它们适用于 Static 变量,我想要 ThreadLocals 用于 non-static 变量
  • 如果 sizeof(T) T mData[tNumThread];。否则会造成由 MESI 协议引起的大瓶颈。

标签: c++ multithreading thread-local


【解决方案1】:

每个线程都有自己的堆栈,记住堆栈帧在函数返回时被弹出(或可以被认为是弹出)。

这就是我们有“stackless python”的原因,因为 1 个堆栈(python 需要什么)和多个线程不能很好地发挥作用(请参阅全局解释器锁)

你可以把它放在 main 中,这样会持续下去,但请记住 C(++) 想在编译时知道所有大小,所以如果线程数发生变化(在编译时不固定),就没有办法知道这一点。

您真正想要的是不在 main 中的东西,但这不会是模板(在数字中),因为在编译时无法知道该数字。

GCC 提供了一个堆栈分配函数(如 malloc),但我找不到它,但最好避免使用它,因为那时优化确实有效。

同样不要低估您的 CPU 预读能力和 GCC 优化,将数组放在堆上也不错。

有趣的阅读与好图片,但不幸的是与主题无关: http://www.nongnu.org/avr-libc/user-manual/malloc.html

【讨论】:

  • 同意最后一段,但是如果我想在数据结构的Nodes 中使用这个类(例如在链表中),我为每个节点分配了两个。所以没有办法避免在堆中分配:(
  • @MohammadRB 所以?如果每个线程都有自己的实例,那也不是线程本地的。我忘记了名字,但现在我得到了问题。 new 非常适合一次发生的大量分配(如果您的对象不断被删除和重新创建,您可能需要一个池),相信 new 和优化器,它们是高级的、生产质量的例程,可以使用。
  • @MohammadRB 为什么我没有打勾?您是否也考虑过使用 C++11 的 thread_local?或者不是将所有副本放在一起,而是在每个线程中创建一个副本并将其添加到“注册表”
  • 在我的问题中查看我的评论。我想要ThreadLocal 不是静态的变量。 C++11s thread_local 仅适用于静态变量。我不明白这一点:'也许在每个线程中创建一个副本并将其添加到“注册表”'
  • @MohammadRB 这些 Ts 属于一个线程,而不是一个注册表(您的 threadlocal 事物是这些 Ts 的列表,而不是注册表,一个列表)并且线程只是......通过 T 访问那里它。为什么不在线程本地创建一个 T (所以它在每个意义上都对线程来说是 blongs)并且 REIGSTER 是一个列表(将 T* 传递到线程本地到注册表的位置,让注册表 register 它在线程 ID 下)记得做访问锁之类的东西,这实际上是一种不受欢迎的方式,线程本地应该是线程本地的。但我假设你有你的理由。
【解决方案2】:

我建议:

std::unordered_map<std::thread::id, T, stackalloc> myTLS;

要么全局锁定所有访问权限,要么提前准备人口并稍后以只读方式访问。

您可以将它与堆栈分配器结合使用。

typedef short_alloc<pair<const thread::id, T>, maxthrds> stackalloc;

https://howardhinnant.github.io/stack_alloc.html

如果你想要其他解决方案,你可以在这里做:

struct Padder
{
    T t;
    char space_[128 - sizeof(T)];  // if sizeof(T) >= 128 just don't include the padding.
};

std::array<Padder, maxthreads> myTLS;

用于 MESI 无瓶颈访问。
使用此方法,您必须关心使用此数组中自己的索引来跟踪线程。

【讨论】:

    猜你喜欢
    • 2014-07-16
    • 1970-01-01
    • 1970-01-01
    • 2021-08-14
    • 1970-01-01
    • 1970-01-01
    • 2021-11-19
    • 2017-05-14
    • 2010-09-24
    相关资源
    最近更新 更多