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
    存储它


  • 将所有内容存储在
    tbb::concurrent_vector
    中,并访问元素w/
    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