xcb_poll_for_event 导致一个 cpu 核心的使用率达到 100%

xcb_poll_for_event causes 100% usage of one cpu core

我正在学习 c 并在 raspberry pi4 上摆弄 xcb lib(而不是 X11)。 问题是当用 xcb_poll_for_event 而不是 xcb_wait_for_event 实现事件循环时,四核中的一个是 100%满的。我究竟做错了什么?使用 wait_for_event(阻塞方式)而不是 xcb_poll_for_event(非阻塞方式)有什么好处吗? 目标是创建一个 window,用户可以在其中与对象 keyboard/mouse/gamepad 进行交互,例如游戏。谁能伸出援手? 相关代码为:

int window_loop_test(xcb_connection_t *connection, Display *display){
  
      /* window loop non blocked waiting for events */
      int running = 1;
      while (running) {
          xcb_generic_event_t *event = xcb_poll_for_event(connection);
          if (event) {
              switch (event->response_type & ~0x80) {
              case XCB_EXPOSE: {
                  // TODO
                  break;
              }
              case XCB_KEY_PRESS: {
                  /* Quit on 'q' key press */
                  /* write key pressed on console */
  
                  const xcb_key_press_event_t *press =
                      (xcb_key_press_event_t *)event;
                  XKeyEvent keyev;
                  keyev.display = display;
                  keyev.keycode = press->detail;
                  keyev.state = press->state;
  
                  char key[32];
  
                  XLookupString(&keyev, key, sizeof(key) - 1, NULL, NULL);
  
                  // key[len] = 0;
                  printf("Key pressed: %s\n", key);
                  printf("Mod state: %d\n", keyev.state);
  
                  if (*key == 'q')
                      running = 0;
  
                  break;
              }
              }
              free(event);
          }
      }
  
      return 0;
  }

轮询和等待各有优势,适用于不同的情况。两者都不是“错误”本身,但您需要针对您的特定用例使用正确的。

xcb_wait_for_event(connection) 是一个 阻塞 调用。在事件可用之前,调用不会 return,并且 return 值是该事件(除非发生错误)。这适用于您只希望线程响应事件但不做任何事情的情况。在这种情况下,当没有事件进入时,无需花费 CPU 资源。

xcb_poll_for_event(connection) 是一个 非阻塞 调用。调用总是立即 returns,但如果没有事件可用,结果将是 NULL。这适用于即使没有事件进入也希望线程能够做有用工作的情况。正如您发现的那样,如果线程只需要响应事件就不好了,因为它可以消耗 CPU 不必要的资源。

您提到您的目标是创建游戏或类似的东西。鉴于构建游戏的方法有很多种,任何一种功能都适合。但是要记住一些基本的事情,它们将决定您要使用哪个功能。可能还有其他注意事项,但这会让您了解需要注意什么。

首先,您的输入系统 运行 是否与其他系统(模拟、渲染等)在同一个线程上?如果是这样,除了等待输入事件之外,保持该线程可用于工作可能很重要。在这种情况下,xcb_poll_for_event() 几乎是必需的,否则您的线程将被阻塞,直到有事件进入。但是,如果您的输入系统在它自己的线程上,不会阻塞您的其他线程,那么它可能是可以接受的使用 xcb_wait_for_event() 并在没有事件进入时让该线程休眠。

第二个考虑因素是您需要以多快的速度响应输入事件。唤醒线程通常会有延迟,因此如果快速响应时间很重要,您首先要避免让线程休眠。同样,在这种情况下,xcb_poll_for_event() 将成为您的朋友。如果响应时间不重要,xcb_wait_for_events() 是一个选项。