2012-05-22 11 views
7

Es scheint plattformbezogen zu sein (funktioniert mit Ubuntu 12.04 auf meinem Laptop, funktioniert nicht mit einem anderen Ubuntu 12.04 auf meiner Workstation).C++ 11 <thread> Multithreads Rendering mit OpenGL verhindert Main Thread liest Stddin

Dies ist ein Beispielcode über was ich mit zwei Threads mache.

#include <iostream> 
#include <thread> 
#include <chrono> 
#include <atomic> 
#include <GL/glfw.h> 

using namespace std; 

int main() { 
    atomic_bool g_run(true); 
    string s; 
    thread t([&]() { 
    cout << "init" << endl; 

    if (!glfwInit()) { 
     cerr << "Failed to initialize GLFW." << endl; 
     abort(); 
    } 

    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 2); 
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 1); 

    if(!glfwOpenWindow(640, 480, 8, 8, 8, 0, 24, 0, GLFW_WINDOW)) { 
     glfwTerminate(); 
     cerr << "Cannot open OpenGL 2.1 render context." << endl; 
     abort(); 
    } 

    cout << "inited" << endl; 

    while (g_run) { 
     // rendering something 
     cout << "render" << endl; 
     this_thread::sleep_for(chrono::seconds(1)); 
    } 
    // unload glfw 
    glfwTerminate(); 
    cout << "quit" << endl; 
    }); 
    __sync_synchronize(); // a barrier added as ildjarn suggested. 
    while (g_run) { 
    cin >> s; 
    cout << "user input: " << s << endl; 
    if (s == "q") { 
     g_run = false; 
     cout << "user interrupt" << endl; 
     cout.flush(); 
    } 
    } 
    __sync_synchronize(); // another barrier 
    t.join(); 
} 

Hier ist meine Kompilierung Parameter:

g++ -std=c++0x -o main main.cc -lpthread -lglfw 

Mein Laptop laufen dieses Programm, wie folgt aus:

init 
inited 
render 
render 
q 
user input: q 
user interrupt 
quit 

und Workstation nur ausgibt:

init 
inited 
render 
render 
q 
render 
q 
render 
q 
render 
^C 

Es ist einfach ignoriert einfach meine Eingaben (ein anderes Programm m gleiches Verfahren mit glew und glfw, springen Sie einfach aus der While-Schleife im Haupt-Thread, ohne meine Eingaben zu lesen.) ABER funktioniert diese Sache normal mit gdb!

keine Ahnung was los ist?

aktualisieren

Nach mehr Tests auf anderen Maschinen, verursacht NVIDIA-Treiber dies. Das gleiche passiert auf anderen Rechnern mit NVIDIA-Grafikkarte.

+4

Versuchen Sie, 'g_run' ein' std :: atomic 'anstatt eine einfache' bool' zu machen. – ildjarn

+0

versucht und funktioniert nicht. In diesem Fall gibt es keine Rennbedingungen, da nur ein Thread darauf schreibt. – xiaoyi

+7

Ein Thread schreibt, während ein anderer liest. Sie ** brauchen ** eine Speicherbarriere. – ildjarn

Antwort

1

Nach mehr Tests auf anderen Maschinen zu lesen, Der Treiber von NVIDIA hat dies verursacht. Das gleiche passiert auf anderen Rechnern mit NVIDIA-Grafikkarte.

Um dieses Problem zu beheben, ist etwas mit der Initialisierungsreihenfolge zu tun. Auf nvidia-Maschinen muss glfw vor allem initialisiert werden (zB create thread, obwohl du die Threadroutine von glfw nicht verwendest.) Die Initialisierung muss abgeschlossen sein, zB das Ausgabefenster nach glfwInit() anlegen, sonst bleibt das Problem bestehen.

Hier ist der feste Code.

#include <iostream> 
#include <thread> 
#include <chrono> 
#include <atomic> 
#include <GL/glfw.h> 

using namespace std; 

int main() { 
    atomic_bool g_run(true); 
    string s; 

    cout << "init" << endl; 

    if (!glfwInit()) { 
    cerr << "Failed to initialize GLFW." << endl; 
    abort(); 
    } 

    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 2); 
    glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 1); 

    if(!glfwOpenWindow(640, 480, 8, 8, 8, 0, 24, 0, GLFW_WINDOW)) { 
    glfwTerminate(); 
    cerr << "Cannot open OpenGL 2.1 render context." << endl; 
    abort(); 
    } 

    cout << "inited" << endl; 

    thread t([&]() { 
    while (g_run) { 
     cin >> s; 
     cout << "user input: " << s << endl; 
     if (s == "q") { 
     g_run = false; 
     cout << "user interrupt" << endl; 
     cout.flush(); 
     } 
    } 
    }); 

    while (g_run) { 
    // rendering something 
    cout << "render" << endl; 
    this_thread::sleep_for(chrono::seconds(1)); 
    } 

    t.join(); 

    // unload glfw 
    glfwTerminate(); 
    cout << "quit" << endl; 
} 

Vielen Dank all Ihre Hilfe.

2

benutzte ich diesen Code mein Programm zu schließen und meine q Schlüssel bekommen seine, wenn

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <pthread.h> 
#include <termios.h> 


static struct termios old, _new; 
static void * breakonret(void *instance); 

/* Initialize _new terminal i/o settings */ 
void initTermios(int echo) 
{ 
tcgetattr(0, &old); /* grab old terminal i/o settings */ 
_new = old; /* make _new settings same as old settings */ 
_new.c_lflag &= ~ICANON; /* disable buffered i/o */ 
_new.c_lflag &= echo ? ECHO : ~ECHO; /* set echo mode */ 
tcsetattr(0, TCSANOW, &_new); /* use these _new terminal i/o settings now */ 
} 

/* Read 1 character with echo */ 
char getche(void) 
{ 
char ch; 
initTermios(1); 
ch = getchar(); 
tcsetattr(0, TCSANOW, &old); 
return ch; 
} 

int main(){ 
pthread_t mthread; 
pthread_create(&mthread, NULL, breakonret, NULL); //initialize break on return 
while(1){ 
    printf("Data on screen\n"); 
    sleep(1); 
} 
pthread_join(mthread, NULL); 
} 
static void * breakonret(void *instance){// you need to press q and return to close it 
char c; 
c = getche(); 
printf("\nyou pressed %c \n", c); 
if(c=='q')exit(0); 
fflush(stdout); 
} 

Mit diesem runing haben Sie einen Thread die Daten von der Tastatur

+0

danke für deine Antwort, es hilft tatsächlich bei meiner anderen [Frage] (http://stackoverflow.com/questions/10663407/stop-repl-from-another-thread). scheint aber ein wenig daneben zu liegen. – xiaoyi