Reputation: 1523
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++;
}
}
Upvotes: 2
Views: 3378
Reputation: 20211
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).
Upvotes: 3
Reputation: 2491
In addition to Girzzly's answer, you do not specify anything private or shared. This usually means you do not controll the access of your memory. You have to define datIt
firstprivate and datIt2
private when you enter the parallel region otherwise everythread overwrites their shared value, which leads to segfaults.
Instead of using locks I would use a critical section, which is more openmpish.
Upvotes: 2