4

アプリケーションを高速化するために、バックグラウンド スレッドにテクスチャを読み込もうとしています。

私たちが使用しているスタックは Linux 上の C/C++ で、gcc でコンパイルされています。OpenGL、GLUT、GLEW を使用しています。テクスチャの読み込みには libSOIL を使用しています。

最終的に、libSOIL を使用してテクスチャ ロードを起動すると、segfault を引き起こす 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

4

1 に答える 1

9

OpenGL呼び出しが正しく動作するためには、OpenGLコンテキストが必要です。コンテキストは、ウィンドウシステムバインディング呼び出し(類似wglCreateContextまたは類似)を使用して作成されます。コンテキストを作成した後、それを「最新にする」必要があります。これは、コンテキストを現在の実行スレッドに関連付けることを意味します。これは、別のウィンドウシステム固有の呼び出し(wglMakeCurrentMicrosoftWindowsやXWindowsなどglXMakeCurrent)を使用して実行されます。GLUTは、その複雑さをすべて抽象化し、を呼び出すときにこれらの操作をすべて実行しますglutCreateWindow

ここで知っておくべき重要なルールは、一度に1つのOpenGLコンテキストのみが実行スレッドに現在存在できるということです。したがって、OPの元の例では、作成したPthreadでコンテキストを最新にすることができれば、メインスレッドでコンテキストが失われます。このすべての一貫性を保つ方法は、単一のスレッドで単一のコンテキストのみを使用することです。(OpenGLコンテキストでデータを共有することは可能ですが、GLUTによって公開されることも、ウィンドウシステムコンテキスト作成呼び出しを使用せずに公開されることもありません)。

あなたの場合、GLUTは、他のスレッドで最新のものにするために、本当に必要なもの(つまり、OpenGLコンテキスト)へのアクセスを許可しない可能性があります。OpenGLコンテキストを自分で作成して管理する必要があります。

于 2013-02-24T21:08:01.220 に答える