我有一个大小为n和n的线程数组,每个i th 线程只能读/写一个数组的i th 单元格。我没有使用任何内存锁。这对C ++ Boost线程安全吗?这与处理器中的缓存有什么关系,存储的内存块,而不是单个值。我想处理器的核心共享缓存并且缓存中没有数据块的重复,因此当对同一块(但在不同位置)进行多次修改时,版本之间不会发生冲突。
答案 0 :(得分:2)
在任何现代处理器上,写入单独的存储位置(即使相邻)都不会造成危险。否则,线程会更加困难。
事实上,拥有线程"填写"这是一个相对常见的习语。数组的元素:这正是线性代数程序的典型线程实现,例如。
答案 1 :(得分:2)
写入单独的内存位置将正常工作,但“错误共享”可能会导致性能问题,具体取决于数据访问模式和特定体系结构。
Oracle's OpenMP API docs对错误分享有很好的描述:
6.2.1什么是虚假分享?
大多数高性能处理器,例如UltraSPARC处理器, 在慢速内存和高速寄存器之间插入缓存缓冲区 的CPU。访问内存位置会导致实际的切片 包含请求的内存位置的内存(缓存行) 复制到缓存中。后续引用相同的内存 可以从缓存中满足位置或周围的位置 直到系统确定有必要保持一致性 缓存和内存之间。
但是,同时更新同一缓存中的各个元素 来自不同处理器的行使整个缓存行无效, 即使这些更新在逻辑上彼此独立。 每个缓存行的单个元素的更新都将该行标记为 无效。其他处理器访问同一个中的不同元素 行看到标记为无效的行。他们被迫取得更多 最近从内存或其他地方复制的行,即使是 访问的元素尚未修改。这是因为缓存 一致性是在缓存行的基础上维护的,而不是针对个人的 元素。结果,互连将会增加 流量和开销。此外,缓存行更新时 进度,禁止访问该行中的元素。
这种情况称为虚假共享。如果经常发生这种情况 OpenMP应用程序的性能和可伸缩性将受到影响 显著。
如果出现以下所有情况,虚假共享会降低性能 条件发生。
- 共享数据由多个处理器修改。
- 多个处理器更新同一缓存行中的数据。
- 此更新非常频繁(例如,在紧密循环中)。
请注意,循环中只读的共享数据不会导致 虚假分享。
答案 2 :(得分:1)
在C ++ 11之前,标准根本没有解决线程问题。现在确实如此。该规则见1.7节:
存储器位置是标量类型的对象或相邻位域的最大序列,所有这些都具有非零宽度。 [注意:该语言的各种功能,例如引用和虚函数,可能涉及程序无法访问但由实现管理的其他内存位置。 - 结束注释]两个或多个执行线程(1.10)可以更新和访问单独的内存位置,而不会相互干扰。
数组不是标量,但它的元素是。因此每个元素都是一个独特的内存位置,因此不同的元素可以同时被不同的线程使用,而不需要锁定或同步(只要最多一个线程访问任何给定的元素)。
但是,如果存储在同一缓存行中的数据由不同的线程写入,则会导致缓存一致性协议的大量额外工作。考虑添加填充或交换数据布局,以便线程使用的所有变量相邻存储。 (结构数组而不是数组结构)