【发布时间】:2012-06-22 00:23:25
【问题描述】:
我正在使用 C++ 开发一个项目,该项目使用自创地图来存储数据 - 从这个意义上说,地图更像是“地理”地图,所以是图像。有不同的线程读取和写入它。地图的数据存储在整数向量的标准向量中。它的大小不变,只是通过getter和setter函数改变某些像素的内容。
我的问题如下: 有时一切都很好,但更多时候我得到损坏的图像,因为像素的值改变了符号或变得与它们应该的完全不同。这可能是对像素的线程读/写访问的问题,如果是这样,我应该使用什么来代替标准向量? 我尝试使用互斥锁来确保只有一个线程读取或写入向量,但是这些读/写操作经常发生,如果我在每次操作时锁定向量,应用程序就会变得太慢。
【问题讨论】:
-
你应该使用一维向量。它的性能优于 2D。
-
原子操作可以解决问题,看看你怎么说“大小不会改变,只有通过 getter 和 setter 函数的某些像素的内容”。此外,尝试对访问进行“分区”(即不同的线程不会同时修改完全相同的像素)以最大程度地减少缓存中毒。当然,这并不能确保两个相邻像素彼此一致,但是如果您以混乱的方式修改它们,再次锁定也不能保证这一点。但是,它将保证,例如同时递增和递减的值不会得到“奇怪”的结果。
-
@Damon:我相信 C++11 中定义的内存模型旨在确保不会发生像您描述的相邻像素的效果。见here。
-
@BjörnPollex:我不明白它是怎么做到的。正确分区(例如,线程 1 在像素 0-999 上运行内核,线程 2 在 1000-1999 上,线程 3 在 2000-2999 上)无论如何都不会发生。然而,想象一下“线程读取和写入”,即线程 1 更新(原子地,正确地)值 20 到 50,而线程 2 读取值 30 和 40 作为输入值以计算值 200。即使两个值都正确更新,也有无法判断整个数据集是否一致没有锁。编译器应该如何在不知道可能正在运行的线程的情况下执行此操作?
-
另一方面,假设线程 1 和 2 都在地图上或多或少相同的区域(重叠)中绘制“山丘”,即它们根据一些距离函数。他们都使用原子增量,并且看到它“正常工作”(尽管它是缓存的噩梦)。在这种情况下,硬件可以发挥所有作用。这在很大程度上取决于您是编写、读取-修改-更新还是读取-修改-更新并读取另一个位置。
标签: c++ multithreading vector