使用glGetString()和linux下的pthreads进行分段错误

时间:2013-02-24 20:14:23

标签: linux opengl pthreads glut glew

我正在尝试在后台线程中加载纹理,以帮助加快我的应用程序。

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

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

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实现,但这也与Ubuntu用于Intel HD显卡的mesa libgl相同。

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

编辑:以下是我的示例测试的#includes和编译字符串:

#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

1 个答案:

答案 0 :(得分:9)

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

现在,要知道的一个重要规则是,任何时候只有一个OpenGL上下文可以是当前执行线程的最新内容。因此,在OP的原始示例中,如果她/他可以在他们创建的Pthread中使上下文变为当前,那么上下文将在主线程中丢失。保持所有这些一致性的方法是仅在单个线程中使用单个上下文。 (OpenGL上下文可以共享数据,但GLUT既不公开,也不使用窗口系统上下文创建调用。)

在您的情况下,GLUT可能不允许访问您真正需要的内容(即OpenGL上下文),以使其在另一个线程中保持最新状态。您需要自己创建和管理OpenGL上下文。