concurrentdvector用于2d数组

时间:2011-11-04 15:10:55

标签: c++ multithreading parallel-processing tbb concurrent-vector

我目前正在尝试使用tbb::concurrent_vector<T>来表示2D数组。这个2d数组将被许多不同的线程访问,这就是为什么我希望它能够最有效地处理并行访问。

我想出了两个解决方案:

  • 使用tbb::concurrent_vector<tbb::concurrent_vector<T> >进行存储。

  • 将所有内容存储在tbb::concurrent_vector<T>和访问元素w / x * width + y

我偏爱第二个,因为我不想锁定整行来访问一个元素(因为我假设要访问元素array[x][y],tbb实现将锁定x第一行,然后是y元素。)

我想知道哪种解决方案对您更好。

2 个答案:

答案 0 :(得分:5)

首先,我认为tbb::concurrent_vector可能存在一些混淆。此容器与std::vector类似,但由于内部存储布局,可以通过线程安全调整大小但访问速度较慢。

您可以详细了解here

在您的情况下,由于您提出的第二个解决方案(带有x * width + y索引的1D数组),我假设您的算法不涉及数组的密集多线程大小调整。因此,与tbb::concurrent_vector等单个线程容器相比,您不会从std::vector中受益。

我猜你假设tbb::concurrent_vector保证了线程安全的元素访问权限,但它没有 - 引自tbb::concurrent_vector ::operator[] doc:

  

获取给定索引处元素的引用。

     

此方法对于并发读取是线程安全的,并且在生成向量时也是如此,只要调用线程检查了该索引

如果你没有调整数组的大小,你只对第一部分感兴趣:线程安全的并发读取。但是std :: vector甚至原始C数组给你的相同。另一方面,它们都不提供线程安全的任意访问(读/写元素)。

您必须使用锁实现它,或者找到另一个为您执行此操作的库(可能是STLPort中的std::vector但我不确定)。虽然这样效率很低,但是因为每次从2D数组访问元素都会涉及线程同步开销。虽然我不知道你究竟想要实现什么,但很可能同步需要比实际计算更长的时间。

现在回答你的问题,即使在单线程设置中,使用一维数组代表ND数组总是更好,因为计算索引(x * width + y)比一个额外的内存访问要快。真正的ND阵列。 对于并发向量,这更加正确,因为在最佳情况下(没有冲突的行访问),您将拥有两倍的锁定开销,并且在存在冲突的情况下会更多。

因此,在您提出的两个解决方案中,我会毫不犹豫地选择第二个:一维数组(不必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

Not_ThreadSafe_Vector可以是任何没有锁定元素访问权限的容器,例如std::vector; ThreadSafe_Vector是一个具有线程安全读/写元素访问权限的容器(不是tbb::concurrent_vector!)。 这样,如果您的访问模式中有一些位置(一个线程更可能访问其先前访问的元素而不是远处),那么可以使每个线程处理来自单个区块的数据。时间,切换到另一个磁贴时只有同步开销。

答案 1 :(得分:-1)

tbb::concurrent_vector是完全线程安全的,用于访问元素(读,写,获取地址)和扩展向量。检查英特尔员工Arch D. Robison here的回复。

但是,清除或销毁向量的操作不是线程安全的(请参阅$ 6.2.1英特尔TBB教程pdf文档)。也就是说,如果clear()上正在进行其他操作,请不要调用tbb::concurrent_vector

正如Antoine所述,由于效率和性能,始终首选将ND阵列处理为一维阵列。