从OpenMP线程调用时,OpenGL调用segfault

时间:2011-02-28 22:05:21

标签: c++ opengl segmentation-fault openmp

首先让我试着说明我想做的事情:

给定一个灰度图像,我想创建256个图层(假设8位图像),其中每个图层是用灰度等级阈值化的图像i - 也是第i层(因此,i = 0: 255)。对于所有这些层,我想计算与我的问题不太相关的各种其他事情,但这应该解释我的代码的结构。

问题是我需要经常执行代码,因此我希望尽可能快地使用很短的时间(因此,只需要简单的加速技巧)。因此,我认为我可以使用OpenMP库,因为我有一个四核,所有内容都是基于CPU的。

这将我带到以下代码,执行正常(至少,它看起来很好:)):

#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遍洪水填充的库,只是为了说明,它不是问题的真正部分。

此代码使用2,3,4,8个线程完成(未测试任何其他数字)。

所以,现在是奇怪的部分。我想添加一些视觉反馈,帮助我调试。对象tmp包含一个名为saveAsTexture()的方法,它基本上为我完成所有工作,并返回纹理ID。这个函数工作正常,单线程,2线程也可以正常工作。但是,一旦超出2个线程,该方法就会导致分段错误。

即使#pragma omp对它很重要(以防saveAsTexture()不是线程安全的),或只执行一次,它仍然会崩溃。这是我添加到上一个循环的代码:

    if(i==100){
        #pragma omp critical
        {
            tmp->saveToTexture();
        }
    }

只执行一次,因为i是迭代器,它是一个关键部分......但是,代码总是在第一次openGL调用时发生段错误(使用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%成功),但是当使用更多线程时执行段错误(执行~25次,0%成功)。并且总是在第一次openGL调用时(例如,如果我删除glPixelStorei(),它会在glDisable()处发生段错误)。 我是否忽略了一些非常明显的事情,我遇到了一个奇怪的OpenMP错误,或者......发生了什么事?

3 个答案:

答案 0 :(得分:4)

您只能从one thread at a time进行OpenGL调用,并且线程必须激活当前上下文。

答案 1 :(得分:2)

OpenGL上下文一次只能由一个线程使用(由wglMakeCurrent / glxMakeCurrent强加的限制)。

但是,你说你正在使用图层。我认为你可以为不同的层使用不同的上下文,WGL_ARB_create_context扩展名(我认为还有一个用于linux)并设置WGL_CONTEXT_LAYER_PLANE_ARB参数。然后你可以为每个线程设置一个不同的上下文,事情应该可以解决。

答案 2 :(得分:1)

非常感谢您的所有答案!现在我知道为什么它失败我决定简单地将所有东西都存储在一个大的3D纹理中(因为这是一个更简单的解决方案),并且只是立即将所有数据发送到GPU。在这种情况下,这很好。