使用OpenMP线程时,
每个线程都可以声明自己的一组私有变量。假设是正确的, 获取每个线程专用的数据的延迟比获取可见数据的延迟要低 到所有线程。换句话说,线程局部变量是缓存?
假设每个线程都想使用线程私有STL数据容器,如std::vector
。在单线程C ++中
代码,std::vector
中的数据存储在堆上。多线程案例怎么样?
thread-private std :: vectors的数据是否仍然存储在堆上?
答案 0 :(得分:5)
除非你使用NUMA机器,否则内存是统一的。
假设获取数据是正确的,这些数据对每个数据都是私有的 线程,比获取所有线程可见的数据具有更低的延迟。
线程本地存储本身并不比所有线程都可见的内存“更快”。但是,仅由一个线程使用的内存不太可能受到缓存一致性影响 - 因为它只能由单个线程访问。
换句话说,是否缓存了线程局部变量?
不一定。如果它不适合CPU缓存,肯定不会是这种情况。共享数据也可以同时存在于多个核心的缓存中。
多线程案例怎么样?是的数据 thread-private std :: vectors仍然存储在堆上?
是的,无论线程数是多少,它们都会在堆中。
答案 1 :(得分:3)
在几乎所有广泛使用的OpenMP运行时中,私有和共享变量的实现方式不同。
private
个自动变量驻留在每个执行线程的堆栈上,threadprivate
个变量驻留在TLS中。自动私有变量也可以优化,以便照常注册。
shared
变量通常实现为一个结构,该结构通过地址作为参数传递给每个线程函数,然后使用附加的指针解引用来访问每个共享变量。除了一些编译器将共享变量视为隐式volatile
并发出全范围的加载/更新/存储指令,尽管OpenMP提供了一个宽松的内存模型,允许不同的共享变量的可见值之间存在某种程度的不一致线程到某些同步点,一个这样的点是明确的flush
指令(仍然flush
是最广泛误解的OpenMP功能,甚至语言制定者也无法在标准文档中使用它们的示例)。
至于在多线程情况下在堆上分配数据,堆操作本质上是序列化的,因为大多数堆实现使用链表或类似的数据结构。除了通常的分配器之外,不关心由不同线程分配的数据是否可能最终共享高速缓存行,并且如果这可能导致错误共享和相关的性能损失。有一些专门的多线程分配器,如hoard
,ptmalloc
,umem
,tcmalloc
等,试图以更多的内存为代价来解决这些问题。其中一些(例如tcmalloc
)也是NUMA感知的。 tcmalloc
文档声称它使某些“魔法”使STL容器使用其分配器而不是默认值,但我不能同意,因为我不是tcmalloc
和C ++的重度用户。
在NUMA系统上运行时要考虑的一件事是线程绑定。一些OpenMP运行时已经包含控制线程与内核绑定的规定,即将推出的OpenMP标准很可能包括用于指定绑定属性的标准框架,因为它现在正在语言委员会中讨论。