C++ C++;11<;螺纹>;使用OpenGL进行多线程渲染可防止主线程读取标准数据

C++ C++;11<;螺纹>;使用OpenGL进行多线程渲染可防止主线程读取标准数据,c++,multithreading,opengl,c++11,glfw,C++,Multithreading,Opengl,C++11,Glfw,它似乎与平台相关(在我的笔记本电脑上与Ubuntu 12.04配合使用,在我的工作站上与另一个Ubuntu 12.04不配合使用) 这是一个关于我用两个线程做什么的示例代码 #include <iostream> #include <thread> #include <chrono> #include <atomic> #include <GL/glfw.h> using namespace std; int main() {

它似乎与平台相关(在我的笔记本电脑上与Ubuntu 12.04配合使用,在我的工作站上与另一个Ubuntu 12.04不配合使用)

这是一个关于我用两个线程做什么的示例代码

#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();
}
我的笔记本电脑运行这个程序,如下所示:

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循环,而不读取我的输入。)但是这件事在gdb中正常工作

知道发生了什么吗

更新


在其他机器上进行更多测试后,NVIDIA的驱动程序导致了这一情况。在使用NVIDIA图形卡的其他机器上也会发生同样的情况。

我使用此代码关闭程序,并在程序运行时获取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);
}
#包括
#包括
#包括
#包括
#包括
静态结构术语旧,新;
静态void*breaknret(void*instance);
/*初始化\u新的终端i/o设置*/
void initTermios(int-echo)
{
tcgetattr(0,&old);/*获取旧的终端i/o设置*/
_新建=旧;/*使新设置与旧设置相同*/
_new.c_lflag&=~ICANON;/*禁用缓冲i/o*/
_new.clflag&=echo?echo:~echo;/*设置回显模式*/
tcsetattr(0、TCSANOW和_new);/*立即使用这些_NewTerminal i/o设置*/
}
/*用echo读取1个字符*/
char getche(无效)
{
char ch;
initTermios(1);
ch=getchar();
tcsetattr(0、TCSANOW和old);
返回ch;
}
int main(){
pthread_t mthread;
pthread_create(&mthread,NULL,breaknret,NULL);//返回时初始化中断
而(1){
printf(“屏幕上的数据”);
睡眠(1);
}
pthread_join(mthread,NULL);
}
静态void*breaknret(void*instance){//您需要按q并返回以关闭它
字符c;
c=getche();
printf(“\n您按了%c\n”,c);
如果(c=='q')退出(0);
fflush(stdout);
}

有了它,你就有了一个从键盘读取数据的线程。在其他机器上进行了更多测试后,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;
}
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
int main(){
原子运行(真);
字符串s;

请尝试使
g_run
a
std::atomic
而不是普通的
bool
。一个线程在写,另一个线程在读。您需要一个内存屏障。也许您应该阅读一下,因为很明显您缺少一个核心概念…(这里的问题是缓存一致性——这与原子性无关。)我在您的第二个输出中没有看到
用户中断
。您能在
cin>>s;
之后添加更多调试日志吗?现在还不清楚-您的主线程没有接收到CPU时钟信号或
if(s==“q”)
由于某些原因不起作用。这不是您的问题的原因,但是比程序的其余部分加起来长一个lambda是令人厌恶的,应该被处以七年编写PHP的惩罚。感谢您的回复,这确实有助于我的另一个问题。但这似乎有点离题。
#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;
}