本文介绍了分割故障openmp错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在建立一个距离矩阵,其中每一行代表一个点,每一列是这一点和数据中的所有其他点之间的距离,我的算法在顺序中非常精细。但是,当我尝试并行化我得到分割错误错误。以下是我的代码并行其中dat是一个包含所有我的数据的地图。任何帮助将非常感激。

 地图< int,string> :: iterator datIt; 
map< int,string> :: iterator datIt2;
map< int,map< int,double> > dist;
int mycont = 0;
datIt = dat.begin();
int size = dat.size();
#pragma omp parallel //构造距离矩阵
{
#pragma omp for
for(int i = 0; i {
datIt2 = dat.find((* datIt).first);
datIt2 ++;
while(datIt2!= dat.end())
{
double ecl = 0;
int c = count((* datIt).second.begin(),(* datIt).second.end(),delm)+1;
string line1 =(* datIt).second;
string line2 =(* datIt2).second;
for(int i = 0; i {
double num1 = atof(line1.substr(0,line1.find_first_of(delm))。
line1 = line1.substr(line1.find_first_of(delm)+1).c_str();
double num2 = atof(line2.substr(0,line2.find_first_of(delm))。c_str());
line2 = line2.substr(line2.find_first_of(delm)+1).c_str();
ecl + =(num1-num2)*(num1-num2);
}
ecl = sqrt(ecl);
dist [(* datIt).first] [(* datIt2).first] = ecl;
dist [(* datIt2).first] [(* datIt).first] = ecl;
datIt2 ++;
}
datIt ++;
}
}


解决方案

I不知道是否是你的代码的唯一问题,但标准容器(如 std :: map )不是线程安全的,至少如果你写它们。因此,如果您对 maps 有任何写访问权,例如 dist [(* datIt).first] [(* datIt2).first] = ecl; 您需要使用 #pragm omp critical 以某种同步结构包装对地图的任何访问> mutexes (omp mutex或,如果使用boost或C ++ 11 boost :: mutex std :: mutex 也是选项):

  //在parallel之前:
omp_lock_t lock;
omp_init_lock(& lock);
...

omp_set_lock(& lock);
dist [(* datIt).first] [(* datIt2).first] = ecl;
dist [(* datIt2).first] [(* datIt).first] = ecl;
omp_unset_lock(& lock);
...

//并行后:
omp_destroy_lock(& lock);

因为你只能读取 dat 没有同步化(至少在C ++ 11中,C ++ 03没有关于threadsafety的保证(因为它没有线程的概念)。通常应该没有同步仍然使用它,但在技术上它的实现依赖因为你没有指定数据共享,所有在 parallel 区域之外声明的变量都被共享。因此,对 datIt datIt2 的写访问也会显示竞争条件。 datIt2 这可以通过指定为私有,或者甚至更好地在第一次使用时声明它来避免:

  map< int,string> :: iterator datIt2 = dat.find((* datIt).first); 


b $ b

解决这个问题为 datIt 有点问题,因为它似乎想要遍历地图的整个长度。最简单的方法(通过使用 O(n)提前每次迭代不过于昂贵)似乎对 datIt ,这是相应的高级(不能保证100%的正确性,只是一个快速的大纲):

  #pragma omp parallel //构造距离矩阵
{
map< int,string> :: iterator datItLocal = datIt;
int lastIdx = 0;
for(int i = 0; i {
std :: advance(datItLocal,i - lastIdx);
lastIdx = i;
//每次在并行中引用datIt时,使用datItLocal而不是datIt
// remove ++ datIt
}
}

这样地图迭代 omp_get_num_threads()次,但它应该工作。如果这是一个不可接受的开销,请查看替代解决方案循环在双向迭代器



作为旁注:也许我错过了一些东西,但对我来说似乎考虑 datIt dat dat.find(datIt-> first)是有点redunant。在映射中应该只有一个元素与给定的键,并且 datIt 指向它,所以这看起来像一个昂贵的方式说 datIt2 = datIt (如果我错了,请纠正我)。


I'm building a distance matrix on which each row represent a point and each column is the distance between this point and all the other points in the data and my algorithm works very fine in the sequentially. However, when I try to parallelize it I get segmentation fault error.The following is my code for parallel where dat is a map that contain all my data. Any help here will be highly appreciated.

map< int,string >::iterator datIt;
map< int,string >::iterator datIt2;
map <int, map< int, double> > dist;
int mycont=0;
datIt=dat.begin();
int size=dat.size();
#pragma omp  parallel //construct the distance matrix
{
  #pragma omp for
  for(int i=0;i<size;i++)
  {
    datIt2=dat.find((*datIt).first);
    datIt2++;
    while(datIt2!=dat.end())
    {
      double ecl=0;
      int c=count((*datIt).second.begin(),(*datIt).second.end(),delm)+1;
      string line1=(*datIt).second;
      string line2=(*datIt2).second;
      for (int i=0;i<c;i++)
      {
        double num1=atof(line1.substr(0,line1.find_first_of(delm)).c_str());
        line1=line1.substr(line1.find_first_of(delm)+1).c_str();
        double num2=atof(line2.substr(0,line2.find_first_of(delm)).c_str());
        line2=line2.substr(line2.find_first_of(delm)+1).c_str();
        ecl += (num1-num2)*(num1-num2);
      }
      ecl=sqrt(ecl);
      dist[(*datIt).first][(*datIt2).first]=ecl;
      dist[(*datIt2).first][(*datIt).first]=ecl;
      datIt2++;
    }
    datIt++;
  }
}
解决方案

I'm not sure if it is the only problem with your code, but standard containers (such as std::map) are not threadsafe, at least if you write to them. So if you have any write access to your maps, such as dist[(*datIt).first][(*datIt2).first]=ecl; you need to wrap any access to the maps in some sort of synchronization structure, either using #pragm omp critical or mutexes (omp mutex or, if you use boost or C++11 boost::mutex or std::mutex are options too):

//before the parallel:
omp_lock_t lock;
omp_init_lock(&lock);
...

omp_set_lock(&lock);
dist[(*datIt).first][(*datIt2).first]=ecl;
dist[(*datIt2).first][(*datIt).first]=ecl;
omp_unset_lock(&lock);
...

//after the parallel:
omp_destroy_lock(&lock);

Since you only read from dat it should be fine without syncronization (in C++11 at least, C++03 has no guarantees about threadsafety whatsoever (since it has no concept of threads). It should typically be fine to use it without synchronization still, but technically its implementation dependent behaviour.

Furthermore since you didn't specify the data sharing all variables declared outside the parallel region are shared by default. Therefore your write access to datIt and datIt2 also present race conditions. For datIt2 this can be avoided by either specifying it as private, or even better declaring it at the point of first use:

map< int,string >::iterator datIt2=dat.find((*datIt).first);

Solving this for datIt is a bit more problematic, since it seems you want to iterate over the whole length of the map. The easiest way (which is not overly costly by using O(n) advance each iteration) seems to operate on a private copy of datIt, which is advanced accordingly (not guaranteeing 100% correctness, just a quick outline):

#pragma omp  parallel //construct the distance matrix
{
   map< int,string >::iterator datItLocal=datIt;
   int lastIdx = 0;
   for(int i=0;i<size;i++)
   {
      std::advance(datItLocal, i - lastIdx);
      lastIdx = i;
      //use datItLocal instead of datIt everytime you reference datIt in the parallel
     //remove ++datIt
   }
}

This way the map is iterated omp_get_num_threads() times, but it should work. If that is an unacceptable overhead for you, look at this answer of mine for alternative solutions for looping on a bidirectional iterator in openmp.

As a sidenote: Maybe I missed something, but to me it seems that considering datIt is an iterator into dat, dat.find(datIt->first) is a bit redunant. There should be only one element in the map with the given key, and datIt points to it, so this seems like an expensive way of saying datIt2=datIt (correct me if I'm wrong).

这篇关于分割故障openmp错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

06-05 08:34