多线程光线跟踪器的噪音

时间:2010-05-27 00:47:31

标签: c++ multithreading thread-safety raytracing

这是我的第一个多线程实现,所以这可能是初学者的错误。线程处理每隔一行像素的渲染(因此所有渲染都在每个线程内处理)。如果线程分别渲染屏幕的上部和下部,问题仍然存在。

两个线程从相同的变量读取,这会导致任何问题吗?据我所知,只有写作会导致并发问题......

调用相同的函数会导致任何并发问题吗?再说一次,据我所知,这应该不是问题......

两个线程写入同一变量的唯一时间是保存计算的像素颜色。它存储在一个数组中,但它们永远不会写入该数组中的相同索引。这会导致问题吗?

Multi-threaded rendered image (垃圾邮件预防阻止我直接发布图片..)

聚苯乙烯。我在两种情况下都使用完全相同的实现,唯一的区别是为渲染创建的单线程和两线程。

2 个答案:

答案 0 :(得分:6)

  

两个线程从相同的变量读取,这会导致任何问题吗?据我所知,只有写作会导致并发问题......

这应该没问题。显然,只要数据在两个线程开始读取之前被初始化,并且在两个线程完成之后就被销毁。

  

调用相同的函数会导致任何并发问题吗?再说一次,据我所知,这应该不是问题......

是和否。没有代码就太难说了。这个功能有什么作用?它是否依赖于共享状态(例如static变量,全局变量,单例......)?如果是的话,那肯定是个问题。如果从来没有任何共享状态,那么你没事。

  

两个线程写入同一变量的唯一时间是保存计算的像素颜色。它存储在一个数组中,但它们永远不会写入该数组中的相同索引。这会导致问题吗?

有时可能。一阵什么?如果sizeof(element) == sizeof(void*)可能是安全的,但C ++标准在多线程上是静音的,因此它不会强迫您的编译器强制您的硬件使其安全。您的平台可能会在这里咬你(例如64位机器和一个写32位的线程可能会覆盖相邻的32位值),但这不是一种罕见的模式。通常你最好使用同步来确定。

您可以通过以下几种方式解决此问题:

  • 每个线程都会构建自己的数据,然后在完成时汇总。
  • 您可以使用mutex保护共享数据。

我的答案中缺乏承诺是使多线程编程变得困难的原因:P

例如,从 Intel® 64 and IA-32 Architectures Software Developer's Manuals开始,描述了不同平台如何保持不同的原子性水平:

  

7.1.1保证原子操作

     

Intel486处理器(以及更新版本   处理器,因为)保证   以下基本内存操作会   总是以原子方式进行:

     
      
  • 读取或写入字节
  •   
  • 读取或写入在16位边界上对齐的字
  •   
  • 读取或写入在32位边界上对齐的双字
  •   
     

奔腾处理器(以及更新版本   处理器,因为)保证   跟随额外的内存操作   将始终以原子方式进行:

     
      
  • 读取或写入在64位边界上对齐的四字
  •   
  • 16位访问适合32位数据总线的未缓存内存位置
  •   
     

P6系列处理器(以及更新版本   处理器以来)保证   以下额外的内存操作   将始终以原子方式进行:

     
      
  • 对缓存线内的高速缓存行的16位,32位和64位未对齐访问
  •   
     

访问可缓存的内存   分割总线宽度,缓存线,   和页面边界不保证   英特尔酷睿2双核处理器,   Intel Atom,Intel Core Duo,Pentium M,   Pentium 4,Intel Xeon,P6系列,   奔腾和Intel486处理器。该   英特尔酷睿2双核,英特尔凌动,英特尔   Core Duo,Pentium M,Pentium 4,Intel   Xeon和P6系列处理器提供   允许的总线控制信号   外部存储器子系统   拆分访问原子;然而,   非对齐数据访问将   严重影响了业绩   处理器,应该避免。

答案 1 :(得分:1)

我已经解决了这个问题,我是通过像Stephen建议的那样单独为每个线程建立数据来做到的(这些元素不是void * size)。谢谢你非常详细的答案!