2017-03-07 100 views
1

项的大小,我需要补矩阵(std::vector< std::vector<T> >)是已知的,已经使用vector::resize(...)功能设置的行和列,其数量。在omp循环中填充已知大小的矩阵。未知

每个矩阵元素的对象都是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<T>::resize(n),向量将确保它自己的动态分配的内存可以包含n类型为T的对象,每个对象都包含一个集合。它会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不从其他线程乱七八糟的数据。

共享存储器编程通常建议分配和线程很可能与内存以后的工作中,初始化的内存。所以,如果你会做更多的myMatrixparallel 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节点上,靠近元素上的线程计算,所以其余并行代码可以高效地进行计算。