2012-05-22 4 views
7

Кажется, что это связано с платформой (работает с Ubuntu 12.04 на моем ноутбуке, не работает с другим Ubuntu 12.04 на моей рабочей станции).C++ 11 <thread> многопоточность рендеринга с OpenGL предотвращает чтение основного потока stdin

Это пример кода о том, что я делаю с двумя потоками.

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

Вот мои параметры компиляции:

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

Мой ноутбук запустить эту программу, как это:

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

и рабочая станция просто выводит:

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

Это просто просто проигнорировал мои входы (еще одна програ с той же процедурой с glew и glfw, просто выпрыгивайте из цикла while в основном потоке, не читая мои входы.) BUT эта вещь работает нормально с gdb!

любая идея о том, что происходит?

Update

После нескольких тестов на других машинах, драйвер NVIDIA, это вызвано. То же самое происходит на других машинах с графической картой NVIDIA.

+4

Попробуйте сделать 'g_run' a' std :: atomic 'вместо простого' bool'. – ildjarn

+0

пробовал и не работает. в этом случае нет гоночных условий, так как на него пишет только один поток. – xiaoyi

+7

Один поток пишет, а другой читает. Вы ** нуждаетесь в ** барьер памяти. – ildjarn

ответ

1

После нескольких тестов на других машинах, Драйвер NVIDIA вызвал это. То же самое происходит на других машинах с графической картой NVIDIA.

Чтобы устранить эту проблему, необходимо выполнить что-то по порядку инициализации. На машинах nvidia glfw нужно инициализировать перед чем-либо (например, создать поток, даже если вы не используете процедуру потоковой обработки glfw). Инициализация должна быть завершена, скажем, создать окно вывода после glfwInit(), в противном случае проблема не исчезнет.

Вот фиксированный код.

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

Спасибо, что вам нравится.

2

Я использовал этот код, чтобы закрыть мою программу и получить свой Q ключ, когда его подножка

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

При этом у вас есть нить читает данные с клавиатуры

+0

спасибо за ваш ответ, это действительно помогает с моей другой [вопрос] (http://stackoverflow.com/questions/10663407/stop-repl-from-another-thread). но кажется немного не по теме для этого. – xiaoyi

Смежные вопросы