Выдержать "паузу" в приложении.

Модераторы: Hawk, Romeo, Absurd, DeeJayC, WinMain

BBB
Сообщения: 1272
Зарегистрирован: 27 дек 2005, 13:37

20 сен 2007, 18:05

Представим себе такую ситуацию.
Имеется Windows-приложение, оконная процедура обработки Windows-событий (не важно, с использованием MFC или нет). И в некоторой точке этой процедуры требуется реализовать следующую логику. Выждать тайм-аут (скажем, минуту), после чего выполнить следующее действие.

Как это красиве сделать?

Тупо выждать Sleep (60000) совсем некрасиво. Так как в этом случае приложение на эту минуту совсем "умрет" - не будет реагировать ни на какие другие события.

То есть, идеально красиво было бы здесь выйти из процедцуры-обработчика событий, а через требуемое время получить какое-то определенное Windows-событие и тут уже продолжить свои дальнейшие действия.

Можно, конечно через SetTimer (... 60000). Т.е. взводим таймер, тут же выходим из обработчика и спокойно ждем, когда таймер опять же вызовет процедцру-обработчик. Там этот таймер убиватся (KillTimer) и делается требуемое действие.
Вроде бы уже красивее, но если такие ситуации в дальнейшем будет возникать постоянно, то хороши ли это будут такие частые установки/убивания таймера? Как это (частые вызовы SetTimer/KillTimer) вообще влияет на ресурсы/производительность Windows?
Опять же MSDN пишет, что таймеры в Windows - ограниченные ресурсы. И, в принципе, вызов SetTimer может обернуться неудачей. Т.е. еще вот такой "подводный камень":

Timers are a limited global resource; therefore it is important that an application check the value returned by the SetTimer member function to verify that a timer is actually available.

Может быть, есть еще какие-то способы?

Заранее спасибо.
Hawk
Сообщения: 215
Зарегистрирован: 17 фев 2004, 14:52
Откуда: СПб
Контактная информация:

20 сен 2007, 18:37

C таймером самое простое, и то что там пишут - ниразу не нарывался на проблему нехватки таймеров.
Но если тебе надо сделать все так уж правильно, то имеет смысл закрутить цикл обработки сообщений в этом месте. Так делают модальные диалоги. В этом случае ничего не "умрет" все события так же будут поступать в оконные обработчики. Разве что в основной цикл обратотки сообщений не будут они проходить, возможно в MFC могут возникнуть накладки.
Но с циклом тоже проблема, стандартная функция GetMessage не подразумевает таймаутов, т.е. если не придет ниодного сообщения так и будет висеть. Так что придется применять что-нить вроде MsgWaitForMultipleObjects.
Аватара пользователя
WinMain
Сообщения: 913
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

20 сен 2007, 18:57

Здесь само собой напрашивается использование потоков и объектов синхронизации, типа Event. А в функции WaitForSingleObject() задать в качестве параметра время ожидания. Тогда не нужен будет никакой цикл. Да и завершить поток при необходимости можно будет досрочно, если принудительно изменить состояние объекта Event.
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

21 сен 2007, 09:45

BBB писал(а):Представим себе такую ситуацию.
Имеется Windows-приложение, оконная процедура обработки Windows-событий (не важно, с использованием MFC или нет). И в некоторой точке этой процедуры требуется реализовать следующую логику. Выждать тайм-аут (скажем, минуту), после чего выполнить следующее действие.
А что, модальный диалог с прогресс-баром показать не судьба?
2B OR NOT(2B) = FF
Hawk
Сообщения: 215
Зарегистрирован: 17 фев 2004, 14:52
Откуда: СПб
Контактная информация:

21 сен 2007, 09:49

WinMain писал(а):Здесь само собой напрашивается использование потоков и объектов синхронизации, типа Event. А в функции WaitForSingleObject() задать в качестве параметра время ожидания. Тогда не нужен будет никакой цикл. Да и завершить поток при необходимости можно будет досрочно, если принудительно изменить состояние объекта Event.
Если в другом потоке то да, а сли хочется сделать паузу в основном потоке, то WaitSingleObject так же остановит поток как и Sleep. Все сильно зависит от того какие глабальные задачи стоят и для чего нужна такая пауза.
BBB
Сообщения: 1272
Зарегистрирован: 27 дек 2005, 13:37

21 сен 2007, 11:46

Absurd писал(а):А что, модальный диалог с прогресс-баром показать не судьба?
То есть?
Аватара пользователя
WinMain
Сообщения: 913
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

21 сен 2007, 12:35

Есть ещё в системе так называемый Waitable Timer. Соответственно, функции для него CreateWaitableTimer() и SetWaitableTimer().
По-моему, это как раз то, что тебе нужно.
Absurd
Сообщения: 1213
Зарегистрирован: 26 фев 2004, 13:24
Откуда: Pietari, Venäjä
Контактная информация:

21 сен 2007, 13:42

BBB писал(а):То есть?
В прямом смысле: пока на экраме модальный диалог, приложение заблокировано до тех пор пока оно (т.е модальное окно) не закроется. Следовательно, надо не размещать на модальном диалоге конпки "Закрыть" и рисовать прогресс-бар чтобы юзверь не думал что программа повисла.
2B OR NOT(2B) = FF
BBB
Сообщения: 1272
Зарегистрирован: 27 дек 2005, 13:37

21 сен 2007, 14:34

Absurd писал(а):В прямом смысле: пока на экраме модальный диалог, приложение заблокировано до тех пор пока оно (т.е модальное окно) не закроется. Следовательно, надо не размещать на модальном диалоге конпки "Закрыть" и рисовать прогресс-бар чтобы юзверь не думал что программа повисла.
Да это вообще предполагается программа, которая без участия пользователя "в автономе" должна работать :)
BBB
Сообщения: 1272
Зарегистрирован: 27 дек 2005, 13:37

21 сен 2007, 14:41

WinMain писал(а):Есть ещё в системе так называемый Waitable Timer. Соответственно, функции для него CreateWaitableTimer() и SetWaitableTimer().
По-моему, это как раз то, что тебе нужно.
Правильно ли я понимаю, что последовательность действий примерно такая:

hTimer = CreateWaitableTimer (NULL, TRUE, NULL); // или 3-й п-ер какое-нибудь имя

Далее, в момент начала паузы:

SetWaitableTimer (hTimer, <интервал_паузы>, 0,
MyCompletionRoutine, // completion routine
&MyArgToCompletionRoutine, // completion routine parameter
0);

По истечении указанного промежутка вызовется MyCompletionRoutine.
А отменить таймер (если до истечения указанного промежутка выясниться, что он уже не актуален):

CancelWaitableTimer (hTimer);

Далее по необходимости возможны повторные вызовы SetWaitableTimer.

Так?
Ответить