只读内存访问的线程安全性

时间:2010-05-04 04:22:27

标签: c thread-safety pthreads

我在C中实现了Barnes-Hut重力算法,如下所示:

  1. 建造一群星团。
  2. 对于每颗恒星,遍历树并应用每个适用节点的重力。
  3. 更新星速和位置。
  4. 阶段2是最昂贵的阶段,因此通过划分星组来并行实施。例如。有1000颗星和2个线程,我有一个线程处理前500颗星,第二个线程处理第二个500颗。

    在实践中,这是有效的:与非线程版本相比,在双核机器上使用两个线程可以将计算速度提高约30%。此外,它产生与原始非线程版本相同的数值结果。

    我担心的是两个线程同时访问相同的资源(即树)。我没有向线程工作者添加任何同步,因此他们可能会尝试在某个时刻从同一位置读取。虽然访问树是严格只读的,但我并不是100%确定它是安全的。它在我测试它时起作用,但我知道这不能保证正确性!

    问题

    • 我是否需要为每个线程制作树的私有副本?
    • 即使它是安全的,是否存在从多个线程访问相同内存的性能问题?

    更新好奇的基准测试结果:

    机器:Intel Atom CPU N270 @ 1.60GHz,cpu MHz 800,缓存大小512 KB

    Threads      real      user      sys
          0    69.056    67.324    1.720
          1    76.821    66.268    5.296
          2    50.272    63.608   10.585
          3    55.510    55.907   13.169
          4    49.789    43.291   29.838
          5    54.245    41.423   31.094
    

    0表示根本没有线程; 1及以上意味着产生许多工作线程和主线程等待它们。我不希望超过2个线程的任何改进,因为它完全受CPU限制,而且有多少核心。有趣的是,奇数个线程比偶数更差。

    sys,显然制作线程需要付出代价。目前它正在为每个帧创建线程(因此N * 1000线程创建)。这很容易编程(今天早上我在火车上的15分钟)。我需要考虑一下如何重用线程...

    更新#2 我已经使用了一个线程池,与两个障碍同步。与每帧重新创建线程相比,这没有明显的性能优势。

2 个答案:

答案 0 :(得分:7)

您没有指定数据的结构,但通常从多个线程同时读取内存是安全的,并且不会引入任何性能问题。如果有人写作,你只会遇到问题。

有趣的是,你说你的两个线程只能获得30%的加速。如果你有一台空闲的机器,两个或多个CPU,只有只读共享数据(即没有同步),我预计会有更接近50%的速度提升。这表明您的操作实际上很快完成,创建线程的开销在您的数字中变得非常重要。你是在超线程CPU上运行吗?

答案 1 :(得分:4)

如果您的数据是只读的,那么不需要,您不需要为每个线程制作树的私有副本。这是共享内存线程模型提供的最大优势!

我不知道这种模型有任何性能问题。如果有的话,它应该更快,这取决于你的CPU是否可以共享一些缓存。