【问题标题】:Avoid local() calls for tbb enumerable_thread_specific variables避免 local() 调用 tbb enumerable_thread_specific 变量
【发布时间】:2019-01-25 22:35:22
【问题描述】:

我有一个使用tbb::enumerable_thread_specific 变量的代码,并且在调用堆栈的深处使用了线程局部变量。幼稚的实现导致大量的local() 函数调用。

现在我想通过分层传递参数来避免local() 函数调用。有没有更简单的方法来做到这一点?如果我不将 Foo 作为参数传递,我有很多地方有 local() 函数调用,但如果我这样做,代码会很混乱。我一直在寻找大小等于线程数的数组的可能用法,并使用thread-id 来访问线程局部变量,但似乎 tbb 没有提供这一点(与 OpenMP 中的omp_get_thread_num() 相比)。

在此处查看更多说明: https://software.intel.com/en-us/forums/intel-threading-building-blocks/topic/804043

【问题讨论】:

    标签: c++ multithreading tbb


    【解决方案1】:

    从 TBB 论坛重复和扩展我自己的答案:

    您可以使用tbb::this_task_arena::max_concurrency()tbb::this_task_arena::current_thread_index() 来实现基于数组的自定义线程本地存储。第一个函数给出了工作线程数的上限;在一定程度上它与omp_get_num_threads() 相当。第二个给出限制内当前线程的索引,类似于omp_get_thread_num()

    【讨论】:

      【解决方案2】:

      瑞恩。在提出其他建议之前,我建议您尽可能使用enumerable_thread_specific。它提供了一个你可能难以理解的特性:每个变量都保证在缓存行上对齐,从而消除了错误共享。

      如果您决定管理自己的线程本地存储,则必须

      1. 分配存储空间
      2. 将存储分配给线程,然后
      3. (可能)释放存储空间。

      还请记住,TBB 不保证特定数量的线程,但通常它会满足您的要求。小心超额认购。

      您可以使用任何未重新分配的存储空间,因此 std::vector<T> 已失效。我建议您使用 concurrent_vector<T>,它不会在扩展数组时移动。

      所以你必须在向量中为每个线程分配一个槽。该索引可以存储在 TLS 中。然后使用此索引从您的concurrent_vector 获取实例。如果向量是碎片化的,这可能是一项昂贵的操作。

      您还可以使用线程的threadID 散列到存储中。如果您愿意分配一次哈希映射并且从不调整大小,这将起作用;否则你必须管理一个哈希表链并遍历链来寻找你的实例。如果我没记错的话enumerable_thread_specific 使用了这种技术。

      您可以看到实现自己的版本并非易事,如果您在每个线程中使用堆栈变量并将其作为形式参数传递,您总是会做得更好。不过,您的问题可能不是这样组织的。

      【讨论】:

      • 关于避免错误共享的一个好点。至于存储重新分配等 - 通常你是对的,但是如果可以提前知道参与线程数的上限,那么很容易避免重新分配。
      猜你喜欢
      • 1970-01-01
      • 2015-01-15
      • 1970-01-01
      • 2011-10-06
      • 2013-10-08
      • 1970-01-01
      • 1970-01-01
      • 2012-12-19
      • 1970-01-01
      相关资源
      最近更新 更多