2012-05-22 12 views
7

Sembra essere correlato alla piattaforma (funziona con Ubuntu 12.04 sul mio portatile, non funziona con un'altra Ubuntu 12.04 sulla mia workstation).C++ 11 <thread> rendering multithreads con OpenGL impedisce la lettura del thread principale stdin

Questo è un codice di esempio su ciò che sto facendo con due thread.

#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(); 
} 

Ecco i miei parametri di compilazione:

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

Il mio computer portatile Esegui questo programma, come questo:

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

e workstation uscite solo:

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

E 'solo semplicemente ignorato i miei input (un altro progra La stessa procedura con glew e glfw, basta saltare fuori dal ciclo while nel thread principale, senza leggere i miei input.) MA questa cosa funziona normalmente con gdb!

qualche idea di cosa sta succedendo?

Aggiornamento

Dopo altri test su altri computer, il driver NVIDIA ha causato questo. La stessa cosa accade su altre macchine con la scheda grafica NVIDIA.

+4

Provare a fare 'g_run' a' std :: atomic 'piuttosto che un semplice' bool'. – ildjarn

+0

provato e non funziona. in questo caso non esiste una condizione di competizione, poiché solo un thread sta scrivendo su di esso. – xiaoyi

+7

Un thread sta scrivendo mentre un altro sta leggendo. Hai ** bisogno ** di una barriera di memoria. – ildjarn

risposta

1

Dopo altri test su altre macchine, Il driver di NVIDIA lo ha causato. La stessa cosa accade su altre macchine con la scheda grafica NVIDIA.

Per risolvere questo problema, c'è qualcosa da fare con l'ordine di inizializzazione. Sui dispositivi nvidia glfw deve essere inizializzato prima di qualsiasi cosa (ad esempio, creare thread, anche se non si utilizza la routine di threading di glfw.) L'inizializzazione deve essere completa, ad esempio, creare la finestra di output dopo glfwInit(), altrimenti il ​​problema persiste.

Ecco il codice fisso.

#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; 
} 

Grazie a tutti gli aiuti.

2

Ho usato questo codice per chiudere il mio programma e ottenere la mia chiave q quando il suo runing

#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); 
} 

Con questo si ha un filo di lettura dei dati dalla tastiera

+0

grazie per la tua risposta, aiuta davvero con la mia altra [domanda] (http://stackoverflow.com/questions/10663407/stop-repl-from-another-thread). ma sembra un po 'fuori tema per questo. – xiaoyi