2013-02-24 46 views
4

我想加载后台线程中的纹理,以帮助加快我的应用程序。使用glGetString()与linux下的pthreads的分段错误

我们使用的堆栈是Linux上的C/C++,使用gcc编译。我们使用OpenGL,GLUT和GLEW。我们一直在使用libSOIL进行纹理加载。

最终,发动纹理加载与libSOIL失败,因为它遇到导致段错误一个glGetString()调用。为了缩小这个问题,我编写了一个非常简单的OpenGL应用程序来重现行为。下面的代码示例不应该“做任何事情”,但它也不应该出现段错误。如果我知道它为什么会这样做,理论上我可以重新编写libSOIL,以便它可以在一个可编程的环境中运行。

void *glPthreadTest(void* arg) { 

    glGetString(GL_EXTENSIONS); //SIGSEGV 
    return NULL; 

} 

int main(int argc, char **argv) { 

    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH); 

    glewInit(); 

    glGetString(GL_EXTENSIONS); // Does not cause SIGSEGV 

    pthread_t id; 
    if (pthread_create(&id, NULL, glPthreadTest, (void*)NULL) != 0) 
    fprintf(stderr, "phtread_create glPthreadTest failed.\n"); 

    glutMainLoop(); 
    return EXIT_SUCCESS; 

} 

从GDB这个应用程序的样本堆栈跟踪看起来是这样的:

#0 0x00000038492f86e9 in glGetString() from /usr/lib64/nvidia/libGL.so.1 
No symbol table info available. 
#1 0x0000000000404425 in glPthreadTest (arg=0x0) at sf.cpp:168 
No locals. 
#2 0x0000003148e07d15 in start_thread (arg=0x7ffff7b36700) at pthread_create.c:308 
     __res = <optimized out> 
     pd = 0x7ffff7b36700 
     now = <optimized out> 
     unwind_buf = {cancel_jmp_buf = {{jmp_buf = {140737349117696, -5802871742031723458, 1, 211665686528, 140737349117696, 0, 5802854601940796478, 
       -5829171783283899330}, mask_was_saved = 0}}, priv = {pad = {0x0, 0x0, 0x0, 0x0}, data = {prev = 0x0, cleanup = 0x0, canceltype = 0}}} 
     not_first_call = 0 
     pagesize_m1 = <optimized out> 
     sp = <optimized out> 
     freesize = <optimized out> 
#3 0x00000031486f246d in clone() at ../sysdeps/unix/sysv/linux/x86_64/clone.S:114 
No locals. 

你会发现我使用的是NVIDIA libGL函数的实现,但是这也与台面相同发生libGL函数,Ubuntu的使用用于英特尔高清显卡。

任何可能出错的提示,或者如何进一步调查以了解发生了什么?

编辑:这里是#包括和我的例子测试编译字符串:

#include <SOIL.h> 
#include <GL/glew.h> 
#include <GL/freeglut.h> 
#include <GL/freeglut_ext.h> 
#include <signal.h> 
#include <pthread.h> 
#include <cstdio> 

g++ -Wall -pedantic -I/usr/include/SOIL -O0 -ggdb -o sf sf.cpp -lSOIL -pthread -lGL -lGLU -lGLEW -lglut -lX11

+0

你还可以添加你用于gcc的标志吗? – derekv 2013-02-24 20:35:35

+0

是的,我更新了我的问题。 – 2013-02-24 21:00:15

回答

8

为了任何的OpenGL调用正常工作,它需要一个OpenGL上下文。上下文是使用窗口系统绑定调用创建的(如wglCreateContext或类似的)。在创建一个上下文后,它需要为“made current”,这意味着将上下文与当前的执行线程关联起来。这是通过另一个特定于窗口系统的调用来完成的(例如用于Microsoft Windows的wglMakeCurrent或用于X Windows的glXMakeCurrent)。 GLUT将所有这些复杂性都从你身上抽象出来,在你拨打glutCreateWindow时做所有这些操作。现在

,要知道一个重要的规则是,只有一个OpenGL上下文可以在任何一个时间是电流执行线程。因此,在OP最初的例子中,如果她/他可以在他们创建的Pthread中创建上下文,那么上下文将会在主线程中丢失。保持所有这些一致的方法是仅在单个线程中使用单个上下文。 (可以让OpenGL上下文共享数据,但这不是GLUT公开的,也不可能不使用窗口系统上下文创建调用)。

在你的情况,很可能是GLUT不允许访问你真正需要(即,OpenGL上下文),以使其在其他线程的电流。你需要自己创建和管理OpenGL上下文。

+1

听起来很合理。我会看看,如果我不能为纹理加载数据的实际负载,这可能会给我我想要的功能。 – 2013-02-24 21:10:58

+1

您肯定能够从另一个文件中读取纹理元素,但是您将无法将其指定为纹理(例如,通过调用'glTexImage2D')。这仍然需要将上下文绑定到另一个线程中,或者理想情况下,每个线程都有一个带有对象共享的上下文。也就是说,你完全可以做你正在问的东西,而不是在GLUT中。 HTH。 – radical7 2013-02-24 21:14:37

+1

@JohnHuston:在单独的线程中从文件加载纹理是合理的。你也可以使用Pixel Buffer Objects将它传递给OpenGL。 PBO有能力映射到客户地址空间,跨越所有线程。所以你可以在OpenGL线程中使用glMapBuffer,并向其他线程发送一些事件的信号。加载器线程填充映射的缓冲区,完成时将OpenGL线程发送给glUnmapBuffer..glTex [Sub]对数据进行映像。 – datenwolf 2013-02-24 21:35:40