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()
是一个选项。
我正在学习 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()
是一个选项。