что я могу использовать, чтобы заменить сон и уснуть в моем приложении Qt? - PullRequest
10 голосов
/ 23 декабря 2009

Я импортирую часть существующего кода в мое приложение Qt и заметил там функцию сна. Я вижу, что этому типу функции нет места в программировании событий. Что я должен сделать вместо этого?

ОБНОВЛЕНИЕ: После обдумывания и обратной связи я бы сказал, что ответ таков: вызовите sleep только за пределами основного потока GUI, и если вам нужно ждать в потоке GUI, используйте processEvents () или цикл обработки событий, это предотвратит зависание GUI .

Ответы [ 5 ]

12 голосов
/ 23 декабря 2009

Это не красиво, но я нашел это в архивах списка рассылки Qt :

Метод сна QThread защищен, но вы можете выставить его следующим образом:

class SleeperThread : public QThread
{
public:
    static void msleep(unsigned long msecs)
    {
        QThread::msleep(msecs);
    }
};

Тогда просто позвоните:

SleeperThread::msleep(1000);

из любой темы.

Однако, более элегантным решением будет рефакторинг вашего кода для использования QTimer - для этого может потребоваться сохранение состояния, чтобы вы знали, что делать, когда таймер отключается.

9 голосов
/ 23 декабря 2009

Я не рекомендую спать в системе, основанной на событиях, но если вы хотите ...
Вы можете использовать условие ожидания, таким образом вы всегда можете прервать сон при необходимости.

//...
QMutex dummy;
dummy.lock();
QWaitCondition waitCondition;
waitCondition.wait(&dummy, waitTime);
//...
6 голосов
/ 23 декабря 2009

Причина, по которой сон является плохой идеей в программировании, основанном на событиях, заключается в том, что программирование на основе событий фактически является формой многозадачности без вытеснения. Вызывая sleep, вы предотвращаете активизацию любого другого события и, следовательно, блокируете обработку потока.

В сценарии ответа на запрос для пакетов udp отправьте запрос и сразу дождитесь ответа. Qt имеет хорошие API сокетов, которые будут гарантировать, что сокет не блокируется во время ожидания события. Событие наступит, когда придет. В вашем случае сигнал QSocket :: readReady - ваш друг.

Если вы хотите запланировать событие на какой-то момент времени в будущем, используйте QTimer. Это гарантирует, что другие события не будут заблокированы.

3 голосов
/ 26 января 2010

Нет необходимости разбивать события вообще. Все, что мне нужно было сделать, это позвонить по номеру QApplication::processEvents(), где было sleep(), и это препятствует зависанию графического интерфейса.

2 голосов
/ 23 декабря 2009

Я не знаю, как QT обрабатывают события внутренне, но в большинстве систем на самом низком уровне жизнь приложения выглядит следующим образом: код основного потока в основном представляет собой цикл ( цикл сообщений ) в котором на каждой итерации приложение вызывает функцию, которая выдает ему новое сообщение; обычно эта функция блокирует, то есть если нет сообщений, функция не возвращается и приложение останавливается.

Каждый раз, когда функция возвращается, приложение получает новое сообщение для обработки, которое обычно имеет некоторого получателя (окно, в которое отправляется), значение (код сообщения, например, указатель мыши был перемещен) и некоторые дополнительные данные (например, мышь была перемещена в координаты 24, 12 ).

Теперь приложение должно обработать сообщение; ОС или инструментарий GUI обычно делают это изнутри, поэтому с некоторой черной магией сообщение отправляется получателю и выполняется правильный обработчик события. Когда обработчик события возвращается, внутренняя функция, которая вызвала обработчик события, возвращает то же самое, что и та, которая вызвала его и т. Д., Пока элемент управления не вернется в основной цикл, который теперь будет снова вызывать магическую функцию извлечения сообщений, чтобы получить другое сообщение. Этот цикл продолжается до тех пор, пока приложение не завершится.

Теперь я написал все это, чтобы вы поняли, почему сон плох в приложении GUI, управляемом событиями: если вы заметите, пока обрабатывается сообщение , никакие другие сообщения не могут быть обработаны , поскольку основной поток занят выполнением вашего обработчика событий, который, в конце концов, является просто функцией, вызываемой циклом сообщений. Таким образом, если вы переведите свой обработчик событий в спящий режим, цикл сообщений также перейдет в спящий режим, что означает, что приложение тем временем не будет получать и обрабатывать любые другие сообщения, включая те, которые заставляют ваше окно перекрашиваться, поэтому ваше приложение будет выглядеть " повесить "с точки зрения пользователя.

Короче говоря: не используйте сон, если вам не нужно спать очень короткое время (максимум несколько сотен миллисекунд), в противном случае графический интерфейс пользователя перестает отвечать на запросы. У вас есть несколько вариантов замены sleep s: вы можете использовать таймер (QTimer), но для этого может потребоваться сделать большую бухгалтерию между событием таймера и другим. Популярной альтернативой является запуск отдельного рабочего потока: он будет просто обрабатывать связь UDP и, будучи отделенным от основного потока, не будет вызывать проблем со сном в случае необходимости. Очевидно, что вы должны позаботиться о защите данных, передаваемых между потоками с помощью мьютексов, и быть осторожными, чтобы избежать условий гонки и других проблем, возникающих при многопоточности.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...