2012-05-22 7 views
7

Parece estar relacionado con la plataforma (funciona con Ubuntu 12.04 en mi computadora portátil, no funciona con otro Ubuntu 12.04 en mi estación de trabajo).C++ 11 <thread> representación multithreads con OpenGL evita el hilo principal lee stdin

Este es un código de muestra sobre lo que estoy haciendo con dos hilos.

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

Aquí está mi parámetros de compilación:

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

Mi portátil de ejecución de este programa, así:

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

y estaciones de trabajo acaba de salidas:

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

Simplemente simplemente ignoró mis entradas (otro programa En el mismo procedimiento con glew y glfw, simplemente salte del ciclo while en el hilo principal, sin leer mis entradas.) PERO ¡Esto funciona normalmente con gdb!

¿alguna idea de lo que está pasando?

actualización

Después de más pruebas en otras máquinas, controlador de NVIDIA causado esto. Lo mismo ocurre en otras máquinas con tarjeta de gráficos NVIDIA.

+4

Intenta hacer 'g_run' a' std :: atomic 'en lugar de un simple' bool'. – ildjarn

+0

intentado y no funciona. no hay condiciones de carrera en este caso, ya que solo un hilo está escribiendo en él. – xiaoyi

+7

Un hilo está escribiendo mientras otro está leyendo. Usted ** necesita ** una barrera de memoria. – ildjarn

Respuesta

1

Después de más pruebas en otras máquinas, El controlador de NVIDIA causó esto. Lo mismo ocurre en otras máquinas con tarjeta de gráficos NVIDIA.

Para solucionar este problema, hay algo que hacer con la orden de inicialización. En las máquinas nvidia debe inicializarse antes de nada (por ejemplo, crear hilo, aunque no esté utilizando la rutina de enhebrado de glfw). La inicialización debe ser completa, por ejemplo, crear la ventana de salida después de glfwInit(), de lo contrario, el problema persiste.

Aquí está el código fijo.

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

Gracias todas sus ayudas.

2

que utiliza este código para cerrar mi programa y conseguir mi llave q cuando su 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 esto usted tiene un hilo de la lectura de los datos de su teclado

+0

gracias por su respuesta, de hecho ayuda con mi otra [pregunta] (http://stackoverflow.com/questions/10663407/stop-repl-from-another-thread). pero parece un poco fuera de tema para esto. – xiaoyi

Cuestiones relacionadas