Позвольте мне начать с попытки указать, что я хочу сделать:
Учитывая изображение в оттенках серого, я хочу создать 256 слоев (при условии 8-битных изображений), где каждый слой - это изображение, пороговое с серыммасштаб i - который также является i-м слоем (поэтому i = 0: 255).Для всех этих уровней я хочу вычислить различные другие вещи, которые не очень относятся к моей проблеме, но это должно объяснить структуру моего кода.
Проблема в том, что мне нужно выполнять код очень часто,поэтому я хочу максимально ускорить процесс, используя короткий промежуток времени (так, только простые приемы ускорения).Поэтому я подумал, что мог бы использовать библиотеку OpenMP, поскольку у меня есть четырехъядерное ядро, и все на данный момент основано на процессорах.
Это подводит меня к следующему коду, который прекрасно работает (по крайней мере, выглядитхорошо :)):
#pragma omp parallel for private(i,out,tmp,cc)
for(i=0; i< numLayers; i++){
cc=new ConnectedComponents(255);
out = (unsigned int *) malloc(in->dimX()* in->dimY()*sizeof(int));
tmp = (*in).dupe();
tmp->threshold((float) i);
if(!tmp){ printf("Could not allocate enough memory\n"); exit(-1); }
cc->connected(tmp->data(),out,tmp->dimX(),tmp->dimY(),std::equal_to<unsigned int>(), true);
free(out);
delete tmp;
delete cc;
}
ConnectedComponents - это просто библиотека, которая реализует двухпроходную заливку, просто для иллюстрации, это на самом деле не является частью проблемы.
Этот код заканчиваетсяхорошо с 2,3,4,8 нитями (не проверял ни одно другое число).
Итак, теперь странная часть.Я хотел добавить визуальную обратную связь, помогая мне отлаживать.Объект tmp
содержит метод с именем saveAsTexture()
, который в основном выполняет всю работу за меня и возвращает идентификатор текстуры.Эта функция прекрасно работает в однопоточном режиме, а также отлично работает с 2 потоками.Тем не менее, как только я выйду за пределы 2 потоков, метод вызовет ошибку сегментации.
Даже если вокруг него критично #pragma omp (на случай, если saveAsTexture()
не является поточно-ориентированным) или выполняется только его выполнениеоднажды все еще падает.Это код, который я добавил в предыдущий цикл:
if(i==100){
#pragma omp critical
{
tmp->saveToTexture();
}
}
, который выполняется только один раз, так как i
является итератором, и это критический раздел ... Тем не менее, код ВСЕГДА segfaultsпри первом вызове openGL (тесты bruteforce с printf (), fflush (stdout)).
Итак, просто чтобы убедиться, что я не пропускаю соответствующую информацию, вот функция saveAsTexture
:
template <class T> GLuint FIELD<T>::saveToTexture() {
unsigned char *buf = (unsigned char*)malloc(dimX()*dimY()*3*sizeof(unsigned char));
if(!buf){ printf("Could not allocate memory\n"); exit(-1); }
float m,M,avg;
minmax(m,M,avg);
const float* d = data();
int j=0;
for(int i=dimY()-1; i>=0; i--) {
for(const float *s=d+dimX()*i, *e=s+dimX(); s<e; s++) {
float r,g,b,v = ((*s)-m)/(M-m);
v = (v>0)?v:0;
if (v>M) { r=g=b=1; }
else { v = (v<1)?v:1; }
r=g=b=v;
buf[j++] = (unsigned char)(int)(255*r);
buf[j++] = (unsigned char)(int)(255*g);
buf[j++] = (unsigned char)(int)(255*b);
}
}
GLuint texid;
glPixelStorei(GL_UNPACK_ALIGNMENT,1);
glDisable(GL_TEXTURE_3D);
glEnable(GL_TEXTURE_2D);
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &texid);
printf("TextureID: %d\n", texid);
fflush(stdout);
glBindTexture(GL_TEXTURE_2D, texid);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, dimX(), dimY(), 0, GL_RGB, GL_UNSIGNED_BYTE, buf);
glBindTexture(GL_TEXTURE_2D, 0);
glDisable(GL_TEXTURE_2D);
free(buf);
return texid;
}
Хорошо отметить, что T
ВСЕГДА является плавающей точкой в моей программе.
Итак, я не понимаю, почему эта программа работает нормально, когда выполняется с 1 или 2 потоками (выполняется~ 25 раз, 100% успеха), но segfaults при использовании большего количества потоков (выполнено ~ 25 раз, 0% успеха).И ВСЕГДА при первом вызове openGL (например, если я удаляю glPixelStorei (), он вызывает ошибку в glDisable ()).Я пропускаю что-то действительно очевидное, сталкиваюсь со странной ошибкой OpenMP или ... что происходит?