如何打断 xcb_wait_for_event?
How do I interrupt xcb_wait_for_event?
在一个单独的线程 (std::thread
) 中,我有一个等待 xcb_wait_for_event
的事件循环。当程序退出时,我想通过中断(我有一个设置线程局部变量的解决方案,循环中的检查点抛出异常)来很好地关闭程序,然后将我的事件线程加入主线程。问题是xcb_wait_for_event
;我需要一种方法 return 早点从它开始,或者我需要一个替代函数。
谁能提出解决方案?感谢您的帮助!
我相信我已经想出了一个合适的解决方案。我已将 xcb_wait_for_event
替换为以下函数:
xcb_generic_event_t *WaitForEvent(xcb_connection_t *XConnection)
{
xcb_generic_event_t *Event = nullptr;
int XCBFileDescriptor = xcb_get_file_descriptor(XConnection);
fd_set FileDescriptors;
struct timespec Timeout = { 0, 250000000 }; // Check for interruptions every 0.25 seconds
while (true)
{
interruptible<std::thread>::check();
FD_ZERO(&FileDescriptors);
FD_SET(XCBFileDescriptor, &FileDescriptors);
if (pselect(XCBFileDescriptor + 1, &FileDescriptors, nullptr, nullptr, &Timeout, nullptr) > 0)
{
if ((Event = xcb_poll_for_event(XConnection)))
break;
}
}
interruptible<std::thread>::check();
return Event;
}
利用 xcb_get_file_descriptor
,我可以使用 pselect
等待直到有新事件,或者直到发生指定的超时。此方法会产生可忽略不计的额外 CPU 成本,固定为 0.0%(在此 i7 上)。唯一的 "downside" 是必须等待最多 0.25 秒来检查中断,我相信可以安全地降低该限制。
一个更简洁的方法是做这样的事情(代码片段是从我目前正在处理的一些代码中提取的):
void QXcbEventQueue::sendCloseConnectionEvent() const {
// A hack to close XCB connection. Apparently XCB does not have any APIs for this?
xcb_client_message_event_t event;
memset(&event, 0, sizeof(event));
event.response_type = XCB_CLIENT_MESSAGE;
event.format = 32;
event.sequence = 0;
event.window = m_connection->clientLeader();
event.type = m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION);
event.data.data32[0] = 0;
xcb_connection_t *c = m_connection->xcb_connection();
xcb_send_event(c, false, m_connection->clientLeader(),
XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<const char *>(&event));
xcb_flush(c); }
对于 _QT_CLOSE_CONNECTION 使用你自己的原子来发出退出信号,在我的例子中,clientLeader() 是一些不可见的 window,它总是出现在我的 X11 连接上。如果您没有任何可以为此目的重复使用的不可见 windows,请创建一个 :)
有了这个,当您看到这个特殊事件到达时,您可以用 xcb_wait_for_event 终止线程。
在一个单独的线程 (std::thread
) 中,我有一个等待 xcb_wait_for_event
的事件循环。当程序退出时,我想通过中断(我有一个设置线程局部变量的解决方案,循环中的检查点抛出异常)来很好地关闭程序,然后将我的事件线程加入主线程。问题是xcb_wait_for_event
;我需要一种方法 return 早点从它开始,或者我需要一个替代函数。
谁能提出解决方案?感谢您的帮助!
我相信我已经想出了一个合适的解决方案。我已将 xcb_wait_for_event
替换为以下函数:
xcb_generic_event_t *WaitForEvent(xcb_connection_t *XConnection)
{
xcb_generic_event_t *Event = nullptr;
int XCBFileDescriptor = xcb_get_file_descriptor(XConnection);
fd_set FileDescriptors;
struct timespec Timeout = { 0, 250000000 }; // Check for interruptions every 0.25 seconds
while (true)
{
interruptible<std::thread>::check();
FD_ZERO(&FileDescriptors);
FD_SET(XCBFileDescriptor, &FileDescriptors);
if (pselect(XCBFileDescriptor + 1, &FileDescriptors, nullptr, nullptr, &Timeout, nullptr) > 0)
{
if ((Event = xcb_poll_for_event(XConnection)))
break;
}
}
interruptible<std::thread>::check();
return Event;
}
利用 xcb_get_file_descriptor
,我可以使用 pselect
等待直到有新事件,或者直到发生指定的超时。此方法会产生可忽略不计的额外 CPU 成本,固定为 0.0%(在此 i7 上)。唯一的 "downside" 是必须等待最多 0.25 秒来检查中断,我相信可以安全地降低该限制。
一个更简洁的方法是做这样的事情(代码片段是从我目前正在处理的一些代码中提取的):
void QXcbEventQueue::sendCloseConnectionEvent() const {
// A hack to close XCB connection. Apparently XCB does not have any APIs for this?
xcb_client_message_event_t event;
memset(&event, 0, sizeof(event));
event.response_type = XCB_CLIENT_MESSAGE;
event.format = 32;
event.sequence = 0;
event.window = m_connection->clientLeader();
event.type = m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION);
event.data.data32[0] = 0;
xcb_connection_t *c = m_connection->xcb_connection();
xcb_send_event(c, false, m_connection->clientLeader(),
XCB_EVENT_MASK_NO_EVENT, reinterpret_cast<const char *>(&event));
xcb_flush(c); }
对于 _QT_CLOSE_CONNECTION 使用你自己的原子来发出退出信号,在我的例子中,clientLeader() 是一些不可见的 window,它总是出现在我的 X11 连接上。如果您没有任何可以为此目的重复使用的不可见 windows,请创建一个 :)
有了这个,当您看到这个特殊事件到达时,您可以用 xcb_wait_for_event 终止线程。