Я пишу графическую программу для Linux на C, используя Xlib. Проблема проста. У меня есть событие, происходящее вне цикла событий Xlib, которое необходимо обработать и которое вызовет некоторые изменения в том, что отображается на экране. В моем случае я пытаюсь заставить курсор мигать внутри текстового поля. Мой цикл событий выглядит так:
XEvent event;
while(window.loop_running == 1) {
XNextEvent(window.dis, &event);
event_handler(&window, &event); // This is a custom function to handle events
}
Решение 1а.
Моей первой мыслью было создать второй цикл с помощью pthreads. Этот второй цикл может обрабатывать асинхронное событие и рисовать на экране по мере необходимости. Однако Xlib плохо работает с несколькими потоками. Даже если я использовал мьютекс для блокировки функции event_handler(), во время асинхронной отрисовки во 2-м цикле у меня все равно периодически возникали сбои из X. Кроме того, если цикл событий не зациклен, примерно после 10 вызовов из цикла pthread, программа зависает.
Решение 1б.
Это можно решить, вызвав XInitThreads() в начале моей программы. Однако это приводит к тому, что valgrind сообщает об утечке памяти. Кажется, что есть некоторая выделенная память, которая не освобождается при выходе. И вызовы XCloseDisplay() просто зависают, если я вызываю XInitThreads(). Я до сих пор не понял, как уничтожать и очищать окна в моей программе, но это лучше оставить для отдельного вопроса. Кроме того, вызов XInitThreads() в начале моей программы предотвращает зависание программы после 10 вызовов из цикла pthread без зацикливания цикла событий. Однако вызовы X начинают блокироваться примерно после 10 вызовов из цикла pthread. Вещи ненадолго возобновляются после циклического цикла событий, например, при наведении указателя мыши на окно. Однако вызовы быстро снова начинают блокироваться, когда активность событий в цикле прекращается. Интересно, что я заметил, что могу воспроизвести эту проблему в некоторых других программах, таких как Bluefish. Если я открою Bluefish, запущу курсор в основное текстовое поле, а затем уберу мышь, примерно через 10 секунд курсор перестанет мигать. Очевидно, что это не всегда проблема, поскольку такие вещи, как дисплей видеоплеера, зависают после некоторого периода отсутствия запуска событий X.
Решение 1c:
Я могу остановить зависание окна, используя XSendEvent() для циклического цикла событий после завершения рисования из цикла pthread. Тем не менее, это кажется действительно Hacky. И я не могу гарантировать, что это сработает, поскольку я точно не знаю, в какой момент X перестанет слушать. Я не смог определить основную причину этой проблемы. Как я уже сказал, кажется, что это происходит примерно через 10 секунд, но это зависит от того, как я изменяю скорость цикла мигающего курсора. У меня возникает соблазн предположить, что это функция реальных вызовов X. Приблизительно 2 на пиксель при перерисовке. Он должен 1) установить цвет переднего плана и 2) нарисовать пиксель из растрового буфера на экран. В настоящее время мое окно поддерживает только разрешение 640x480. Конечно, я просто предполагаю, что это можно использовать для определения точки отказа, поскольку я действительно не знаю причины.
Решение 2.
Я могу отказаться от всего этого и повторно реализовать цикл событий, опрашивая очередь событий с помощью XEventsQueued() и обрабатывая их по мере их поступления. Но я буду честен, я ненавижу это решение. Это действительно хакерское решение, которое увеличит вычислительную мощность, необходимую для этого приложения, и увеличит задержку ответа на событие, поскольку я хотел бы приостановить поток между опросами, чтобы предотвратить просто вращение потока и привязку ядра ЦП. Я пишу эту программу с целью сделать ее быстрой, стабильной и компактной.
у кого-нибудь есть решение? Это такая простая и фундаментальная проблема, но я видел только примеры приложений, которые используют XNextEvent в цикле обработки событий. Я не нашел примеров того, как обрабатывать события вне цикла событий. Спасибо за помощь. Я новый участник Stack Overflow. Это мой первый пост. Так что извиняюсь, если ошибся.
poll()
с fd, полученным с помощьюConnectionNumber()
, и fds, на которые приходят ваши другие события. Когда X11 fd готов, вы обрабатываете события с помощьюwhile(XPending()){ XNextEvent(); ... }
. Даже в этом случае функции X11, имеющие форму запроса/ответа (например,XQueryTree
), могут остановить ваш цикл обработки событий. Решение состоит в том, чтобы переключиться на xcb (где вы можете разделить их на части запроса/ответа). ИМХО, xcb такой же уродливый и не намного лучше, чем Xlib, но это единственное, что доступно. - person mosvy   schedule 14.04.2020