在c ++(boost)中通过许多线程安全地修改数组的各种单元格

时间:2014-06-11 00:19:17

标签: c++ arrays multithreading boost

我有一个大小为n和n的线程数组,每个i th 线程只能读/写一个数组的i th 单元格。我没有使用任何内存锁。这对C ++ Boost线程安全吗?这与处理器中的缓存有什么关系,存储的内存块,而不是单个值。我想处理器的核心共享缓存并且缓存中没有数据块的重复,因此当对同一块(但在不同位置)进行多次修改时,版本之间不会发生冲突。

3 个答案:

答案 0 :(得分:2)

在任何现代处理器上,写入单独的存储位置(即使相邻)都不会造成危险。否则,线程会更加困难。

事实上,拥有线程"填写"这是一个相对常见的习语。数组的元素:这正是线性代数程序的典型线程实现,例如。

答案 1 :(得分:2)

写入单独的内存位置将正常工作,但“错误共享”可能会导致性能问题,具体取决于数据访问模式和特定体系结构。

Oracle's OpenMP API docs对错误分享有很好的描述:

  

6.2.1什么是虚假分享?

     

大多数高性能处理器,例如UltraSPARC处理器,   在慢速内存和高速寄存器之间插入缓存缓冲区   的CPU。访问内存位置会导致实际的切片   包含请求的内存位置的内存(缓存行)   复制到缓存中。后续引用相同的内存   可以从缓存中满足位置或周围的位置   直到系统确定有必要保持一致性   缓存和内存之间。

     

但是,同时更新同一缓存中的各个元素   来自不同处理器的行使整个缓存行无效,   即使这些更新在逻辑上彼此独立。   每个缓存行的单个元素的更新都将该行标记为   无效。其他处理器访问同一个中的不同元素   行看到标记为无效的行。他们被迫取得更多   最近从内存或其他地方复制的行,即使是   访问的元素尚未修改。这是因为缓存   一致性是在缓存行的基础上维护的,而不是针对个人的   元素。结果,互连将会增加   流量和开销。此外,缓存行更新时   进度,禁止访问该行中的元素。

     

这种情况称为虚假共享。如果经常发生这种情况   OpenMP应用程序的性能和可伸缩性将受到影响   显著。

     

如果出现以下所有情况,虚假共享会降低性能   条件发生。

     
      
  • 共享数据由多个处理器修改。
  •   
  • 多个处理器更新同一缓存行中的数据。
  •   
  • 此更新非常频繁(例如,在紧密循环中)。
  •   
     

请注意,循环中只读的共享数据不会导致   虚假分享。

答案 2 :(得分:1)

在C ++ 11之前,标准根本没有解决线程问题。现在确实如此。该规则见1.7节:

  

存储器位置是标量类型的对象或相邻位域的最大序列,所有这些都具有非零宽度。 [注意:该语言的各种功能,例如引用和虚函数,可能涉及程序无法访问但由实现管理的其他内存位置。 - 结束注释]两个或多个执行线程(1.10)可以更新和访问单独的内存位置,而不会相互干扰。

数组不是标量,但它的元素是。因此每个元素都是一个独特的内存位置,因此不同的元素可以同时被不同的线程使用,而不需要锁定或同步(只要最多一个线程访问任何给定的元素)。

但是,如果存储在同一缓存行中的数据由不同的线程写入,则会导致缓存一致性协议的大量额外工作。考虑添加填充或交换数据布局,以便线程使用的所有变量相邻存储。 (结构数组而不是数组结构)