Как мне прервать xcb_wait_for_event?

В отдельной ветке (std::thread), У меня есть цикл событий, который ждет xcb_wait_for_event, Когда программа завершается, я хотел бы аккуратно завершить работу, прервав (у меня есть решение, которое устанавливает локальную переменную потока, а контрольные точки в цикле генерируют исключение), а затем присоединяет мой поток событий к основному потоку. Вопрос xcb_wait_for_event; Мне нужен способ вернуться из этого раньше, или мне нужна альтернатива функции.

Кто-нибудь может предложить решение? Спасибо за вашу помощь!

1

Решение

Более аккуратным способом было бы сделать что-то вроде этого (фрагмент кода извлечен из некоторого кода, над которым я сейчас работаю):

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, когда увидите, что поступает это специальное событие.

1

Другие решения

Я считаю, что нашел подходящее решение. Я заменил 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 секунды для проверки прерываний, и я уверен, что лимит можно было бы безопасно снизить.

2

По вопросам рекламы [email protected]