В отдельной ветке (std::thread
), У меня есть цикл событий, который ждет xcb_wait_for_event
, Когда программа завершается, я хотел бы аккуратно завершить работу, прервав (у меня есть решение, которое устанавливает локальную переменную потока, а контрольные точки в цикле генерируют исключение), а затем присоединяет мой поток событий к основному потоку. Вопрос xcb_wait_for_event
; Мне нужен способ вернуться из этого раньше, или мне нужна альтернатива функции.
Кто-нибудь может предложить решение? Спасибо за вашу помощь!
Более аккуратным способом было бы сделать что-то вроде этого (фрагмент кода извлечен из некоторого кода, над которым я сейчас работаю):
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 () — это невидимое окно, которое всегда присутствует в моем соединении X11. Если у вас нет невидимых окон, которые можно было бы использовать для этой цели, создайте их 🙂
При этом вы можете прекратить поток с помощью xcb_wait_for_event, когда увидите, что поступает это специальное событие.
Я считаю, что нашел подходящее решение. Я заменил 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
ждать, пока не появятся новые события, или пока не истечет указанное время ожидания. Этот метод приводит к незначительным дополнительным затратам на процессор, оставаясь на уровне 0.0% (на этом i7). Единственный «недостаток» — это ожидание максимум 0,25 секунды для проверки прерываний, и я уверен, что лимит можно было бы безопасно снизить.