2012-07-15 27 views
2

虽然使用OpenMP线程,OpenMP的线程,数据访问延迟和STL数据容器

  1. 每个线程都可以宣布自己的一套私有变量。假设 获取每个线程专用的数据的延迟低于将数据可见 提取到所有线程的延迟时间是否正确?换句话说,线程局部变量缓存了

  2. 说每个线程,想要使用线程私有STL数据容器,如std::vector。在单线程C++ 代码中,std::vector中的数据存储在堆中。那么多线程的情况呢? 线程专用std ::向量的数据是否仍然存储在堆上?

回答

5

除非您使用的是NUMA机器,否则内存是统一的。

是否正确地假设,获取每个线程专用的数据的延迟低于获取所有线程可见的数据的延迟。

线程本地存储本质上并不比所有线程都可见的内存“更快”。但是,仅由一个线程使用的内存不太可能受到缓存一致性影响 - 因为它只能由单个线程访问。

换句话说,线程局部变量是否被缓存?

不一定。如果它不适合CPU缓存,它肯定不会是这种情况。共享数据同时也可以位于多个内核的缓存中。

那么多线程的情况呢? 线程专用std ::向量的数据是否仍然存储在堆中?

是的,无论线程的数量如何,他们都会在堆中。

+0

重回你的第一句话,这是真的吗?这与你的第二段有些矛盾,这也回应了我的理解。 – 2012-07-15 16:11:12

+0

是的,我做了一个项目,我手动将数据分配到不同的NUMA节点,并将关联的线程绑定到这些节点。 (因此是“微观管理”部分) – Mysticial 2012-07-15 16:12:00

+0

我的意思是“内存或多或少是统一的”部分,而不是“除非”部分。 NUMA允许你有非统一的访问权限是无可争议的。 – 2012-07-15 16:13:33

3

在几乎所有广泛使用的OpenMP运行时中,私有变量和共享变量的实现都是不同的。

private自动变量驻留在每个正在执行的线程的堆栈中,并且threadprivate变量驻留在TLS中。自动私有变量也可以进行优化以照常注册。

shared并行区域的变量通常实现为一个结构,它通过地址作为参数传递给每个线程函数,然后使用额外的指针取消引用来访问每个共享变量。除了一些编译器将共享变量视为隐含地处理volatile并发布全部加载/更新/存储指令的范围,尽管OpenMP提供了一种宽松的内存模型,允许不同线程中共享变量的可见值之间存在某种程度的不一致性同步点,其中一个点是明确的flush指令(仍然flush是最广泛误解的OpenMP功能,甚至语言制造者也无法在标准文档中获得其使用权范例)。

至于在多线程情况下在堆中分配数据,堆操作本质上是序列化的,因为大多数堆实现使用链接列表或类似的数据结构。除了通常的分配器不关心由不同线程分配的数据可能最终共享高速缓存行,并且这可能导致错误的共享和相关的性能损失。有专门的多线程分配器,如hoard,ptmalloc,umem,tcmalloc等,试图解决这些问题的代价是更多的内存使用。其中一些(例如tcmalloc)也支持NUMA。 docs声称它做了某种“魔术”来让STL容器使用它的分配器而不是默认的分配器,但我不能赞同,因为我不是tcmalloc和C++的重量级用户。

在NUMA系统上运行时需要考虑的一件事是线程绑定。一些OpenMP运行时已经包含了控制线程与内核绑定的规定,并且即将颁布的OpenMP标准很可能包含用于指定绑定属性的标准框架,正如语言委员会正在讨论的那样。