在 omp 循环中填充已知大小的矩阵。条目大小未知

Posted

技术标签:

【中文标题】在 omp 循环中填充已知大小的矩阵。条目大小未知【英文标题】:Fill a matrix of known size in an omp loop. Size of entries unknown 【发布时间】:2017-03-07 09:41:03 【问题描述】:

我需要填充一个矩阵 (std::vector< std::vector<T> >),其行数和列数是已知的,并且已经使用 vector::resize( ... ) 函数设置。

每个矩阵元素的对象都是class T 的对象,它们应该有一个std::set<int> 作为其中的成员。无法提前知道这些集合的大小。

为了填充矩阵,我打算使用如下循环,其中 m、n 是已知数字:

std::vector< T > innerVector;
innerVector.resize( n, T() );

std::vector< std::vector< T > > myMatrix;
myMatrix.resize( m, innerVector );

#pragma omp parallel for
for( size_t i = 0; i < myMatrix.size(); ++i )

    for( size_t j = 0; j < myMatrix.at(0).size(); ++j )
    
        fillMatrix( myMatrix, i, j);
    

fillMatrix( ... ) 函数只使用已知信息来构建包含在每个矩阵元素中的数字集,因此没有数据依赖性。

像这样填充矩阵,我们不会遇到由多个线程一次访问矩阵元素引起的竞争条件。我的问题是在不使用omp critical 环境的情况下调用fillMatrix( ... ) 函数是否安全。

关键是我不知道vector::resize( ... ) 函数是如何工作的。不知何故,它为myMatrix 分配了一些内存,但由于class T 的元素大小未知,我可以想象遇到这种情况,最初为矩阵元素分配的内存是不够的。那会发生什么?是否有可能多个线程(即填充不同矩阵条目的线程)尝试使用相同的地址扩展分配的内存?

【问题讨论】:

【参考方案1】:

许多复杂的对象,例如std::vectorstd::set,由对象本身的内存(即sizeof(std::vector) 字节)和其后面的附加动态分配内存组成。对于您的示例,集合元素通常存储在树的动态分配节点中。因此,如果您执行std::vector&lt;T&gt;::resize(n),向量将确保它自己的动态分配内存可以包含T 类型的n 对象,每个对象都包含一个集合。它会default-construct那些元素使用这个当你稍后将元素添加到T内的集合中时,将为集合的树节点分配新的内存块。

按照您描述的方式,就正确性而言,您应该没问题。但是,我强烈建议您在界面中澄清这一点:

void fillMatrix(T&, size_t, size_t);
...
fillMatrix(myMatrix[i][j], i, j);

甚至:

T fillMatrix(size_t, size_t);
...
myMatrix[i][j] = fillMatrix(i, j);

这样,fillMatrix 不会弄乱其他线程的数据就更清楚了。

共享内存编程中的一般建议是在稍后可能使用该内存的线程上分配和初始化内存。因此,如果您要在myMatrix 上做更多的parallel for,请考虑以下事项:

std::vector< std::vector< T > > myMatrix;
myMatrix.resize( m );

#pragma omp parallel for
for( size_t i = 0; i < myMatrix.size(); ++i )

    myMatrix.at( i ).resize( n ); // Ommiting T() is a bit more efficient
    for( size_t j = 0; j < n; ++j )
    
        fillMatrix( myMatrix, i, j);
    

但是,无论如何,代码可能会受到内存分配的限制(用于向std::setstd::vector::resize 添加元素)。因此,除非fillMatrix 进行大量额外的计算,否则您不应期望代码的特定部分的并行性能提高。但是,数据可能位于靠近元素的线程计算的缓存/NUMA 节点中,因此您的并行代码的其余部分可以有效地计算。

【讨论】:

以上是关于在 omp 循环中填充已知大小的矩阵。条目大小未知的主要内容,如果未能解决你的问题,请参考以下文章

在未知大小的容器中居中多个 DIV

如何填充包含未知大小的结构切片的结构[重复]

execl vs execv,参数大小未知

如何在 for 循环中添加不同大小的 numpy 数组条目(类似于 Matlab 的单元格数组)?

如何在大小未知时使用 while..do 循环初始化 F# 列表

Google Big Query 的列大小