代码之家  ›  专栏  ›  技术社区  ›  Edmund

只读存储器访问的线程安全

  •  4
  • Edmund  · 技术社区  · 15 年前

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

    1. 建造一棵群星之树。
    2. 对于每颗恒星,穿过树并施加来自每个适用节点的引力。
    3. 更新恒星速度和位置。

    第二阶段是最昂贵的阶段,因此是通过划分恒星集合并行实现的。例如,使用1000个星和2个线程,我有一个线程处理前500个星,第二个线程处理后500个星。

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

    我担心的是这两个线程同时访问同一个资源(即树)。我没有给线程工作器添加任何同步,因此它们可能会在某个时间尝试从同一位置读取数据。尽管对树的访问是严格的只读的,但我不能百分之百地肯定它是安全的。当我测试过它的时候它已经工作了,但是我知道这并不能保证它是正确的!

    问题

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

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

    机器: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 回复  |  直到 15 年前
        1
  •  7
  •   Stewart    15 年前

    您不指定数据的结构,但通常从多个线程同时读取内存是安全的,不会带来任何性能问题。只有当有人在写作时你才会遇到问题。

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

        2
  •  4
  •   Chris AtLee    15 年前

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

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