C++ 二维阵列的并行_矢量
我目前正在尝试使用C++ 二维阵列的并行_矢量,c++,multithreading,parallel-processing,tbb,concurrent-vector,C++,Multithreading,Parallel Processing,Tbb,Concurrent Vector,我目前正在尝试使用tbb::concurrent_vector表示二维数组。这个2d数组将被许多不同的线程访问,这就是为什么我希望它能够尽可能高效地处理并行访问 我提出了两个解决方案: 使用tbb::concurrent_vector存储它 将所有内容存储在tbb::concurrent_vector中,并访问元素w/x*width+y 我更喜欢第二行,因为我不想锁定整行来访问一个元素(因为我假设要访问元素array[x][y],tbb实现将锁定xth行,然后锁定yth元素) 我想知道您认为
tbb::concurrent_vector
表示二维数组。这个2d数组将被许多不同的线程访问,这就是为什么我希望它能够尽可能高效地处理并行访问
我提出了两个解决方案:
- 使用
存储它tbb::concurrent_vector
- 将所有内容存储在
中,并访问元素w/tbb::concurrent_vector
x*width+y
array[x][y]
,tbb实现将锁定x
th行,然后锁定y
th元素)
我想知道您认为哪种解决方案更好。首先,我认为可能会对
tbb::concurrent_vector
产生一些混淆。此容器类似于std::vector
,但具有线程安全的大小调整功能,但由于内部存储布局,元素访问速度较慢
你可以阅读更多关于它的内容
在您的例子中,由于您提出的第二种解决方案(1D数组,具有
x*width+y
索引),我假设您的算法不涉及数组的密集多线程调整。因此,与像std::vector
这样的单线程容器相比,您不会从tbb::concurrent\u vector
中获益
我猜您假定
tbb::concurrent_vector
保证了线程安全的元素访问,但它没有引用::operator[]
doc:
获取对给定索引处元素的引用
此方法对于并发读取是线程安全的,并且在增加向量时也是如此,只要调用线程检查了该索引
如果不调整数组的大小,您只对第一部分感兴趣:线程安全并发读取。但是std::vector甚至原始的C数组都提供了相同的结果。另一方面,两者都不提供线程安全的任意访问(读/写元素)
您必须使用锁来实现它,或者找到另一个为您实现此功能的库(可能是STLPort中的std::vector
,但我不确定)。尽管这会非常低效,因为每次从2D数组访问元素都会涉及线程同步开销。虽然我不知道您到底想实现什么,但很有可能同步所花费的时间比您实际的计算时间要长
现在回答您的问题,即使在单线程设置中,也最好使用1D数组来表示ND数组,因为计算索引(x*width+y)比真正的ND数组所需的额外内存访问速度更快。
对于并发向量,这一点更为正确,因为在最佳情况下(没有冲突的行访问),锁开销将增加一倍,在有冲突的情况下,锁开销会增加很多
因此,在您提出的两种解决方案中,我会毫不犹豫地选择第二种:1D数组(无需
tbb::concurrent_vector
),具有足够的元素访问锁定
根据您的算法和不同线程的访问模式,图像编辑软件(gimp、photoshop…)中使用的另一种方法是基于分片的:
template<typename T> struct Tile {
int offsetX, int offsetY;
int width, height;
Not_ThreadSafe_Vector<T> data;
};
ThreadSafe_Vector< Tile<T> > data
模板结构平铺{
int offsetX,int offsetY;
int宽度、高度;
非线程安全向量数据;
};
线程安全_向量数据
其中
Not_ThreadSafe\u Vector
可以是任何不锁定元素访问的容器,例如std::Vector
;而ThreadSafe\u Vector
是一个具有线程安全读/写元素访问权限的容器(而不是tbb::concurrent\u Vector
!)。
这样,如果您的访问模式中有一些局部性(线程更可能访问靠近其先前访问的元素,而不是远离它的元素),那么可以让每个线程在大多数时间处理来自单个磁贴的数据,切换到另一个磁贴时,您只会有同步开销。
tbb::concurrent_vector
对于访问元素(读取、写入、获取地址)和增加向量是完全线程安全的。查看英特尔员工Arch D.Robison的回复
但是,清除或销毁向量的操作不是线程安全的(请参阅$6.2.1英特尔TBB教程pdf文档)。也就是说,如果在
tbb::concurrent_vector
上有其他正在进行的操作,则不要调用clear()
正如Antoine提到的,由于效率和性能,将ND阵列作为1D阵列处理始终是首选。关于std::vector
?我不知道足够的TBB来回答,但我觉得这很好。好吧,如果std::vector
包含行(TBB::concurrent_vector
),例如,如果我尝试在一个线程中添加新行,在另一个线程中删除一行,我会遇到麻烦。这可能取决于您希望容器处理的并发操作。tbb::concurrent_vector
对于访问元素来说不是完全线程安全的。Arch的短语“concurrent_vector允许多个线程访问(读取、写入、获取地址)同一元素。它不会序列化访问,因此这些访问是否安全取决于数据类型。”表示您可以同时访问元素,但安全性取决于特定的元素类型。@Alex不确定我是否理解。您是否有两种数据类型之间存在潜在差异的示例,以及这会导致什么?如果tbb::concurrent_vector
不是线程安全的,那么为什么要这样做?序列化访问不是线程安全。这完全是另一回事(尽管你在下面划线是件好事)。同样,它是线程安全的,除非还有其他我不明白的地方。tbb::concurrent_vector
提供了容器范围内的线程安全操作,例如push_-back