1

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

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

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

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

多线程渲染图像 (防止垃圾邮件阻止我直接发布图像..)

附言。我在这两种情况下都使用完全相同的实现,唯一的区别是为渲染创建了一个线程和两个线程。

4

2 回答 2

6

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

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

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

是和不是。没有代码很难说。函数有什么作用?它是否依赖于共享状态(例如static变量、全局变量、单例...)?如果是,那么这绝对是一个问题。如果从来没有任何共享状态,那么你就可以了。

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

也许有时候。什么数组?if 可能是安全的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 位边界上对齐的双字

Pentium 处理器(以及之后的更新处理器)保证以下额外的内存操作将始终以原子方式执行:

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

P6 系列处理器(以及之后的更新处理器)保证以下附加内存操作将始终以原子方式执行:

  • 对适合高速缓存行的高速缓存内存进行未对齐的 16、32 和 64 位访问

Intel Core 2 Duo、Intel Atom、Intel Core Duo、Pentium M、Pentium 4、Intel Xeon、P6 系列、Pentium 不保证对跨总线宽度、缓存行和页面边界拆分的可缓存内存的访问是原子的, 和 Intel486 处理器。Intel Core 2 Duo、Intel Atom、Intel Core Duo、Pentium M、Pentium 4、Intel Xeon 和 P6 系列处理器提供总线控制信号,允许外部存储器子系统使分离访问原子化;但是,不对齐的数据访问会严重影响处理器的性能,应该避免。

于 2010-05-27T01:01:32.740 回答
1

我已经解决了这个问题,我按照斯蒂芬的建议(不是 void* 大小的元素)分别为每个线程构建数据来做到这一点。感谢您提供非常详细的答案!

于 2010-05-30T19:20:27.343 回答