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

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

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

21 сен 2007, 19:13

Попробовал с WaitableTimer, что-то не получается.

Написал с вызовом callback-функции:

SetWaitableTimer (hTimer, &tm, 0,
MyCompletionRoutine, // completion routine
&MyArgToCompletionRoutine, // completion routine parameter
0);

Нифига она не вызывается :(
Интервал ставил 15 секунд:

tm.QuadPart = -150000000;

Насторожила строка в MSDN:

The completion routine is executed by the thread that activates the timer using SetWaitableTimer. However, the thread must be in an alertable state.

Может, в данном случае этого "стейта" и нет...
Аватара пользователя
WinMain
Сообщения: 913
Зарегистрирован: 14 янв 2005, 10:30
Откуда: Москва
Контактная информация:

22 сен 2007, 23:17

Удобнее использовать не голые Win32API-функции, а применить класс-обёртку на С++. Набери в поисковике что-нибудь типа "CWaitableTimer".
Hawk
Сообщения: 215
Зарегистрирован: 17 фев 2004, 14:52
Откуда: СПб
Контактная информация:

24 сен 2007, 13:07

WaitableTimer по тому и Waitable, что предполагается его ждать функциями WaitFor..Object(s). А данном случае никакого смысла его использовать нету. Проще обычным Sleep или теми же Wait... с таймаутом необходимым - результат будет такой же. А именно блокировка потока до истечения какого-то времени. Если не хочется блокировать поток, то без цикла обработки сообщений не обойтись.
Но кстати тут и может пригодиться WaitableTimer чтобы ждать его в MsgWaitFor...
Вот пример из MSDN цикла сообщений с ожиданием событий

Код: Выделить всё

int MessageLoop ( 
    HANDLE* lphObjects,  // handles that need to be waited on 
    int     cObjects     // number of handles to wait on 
  )
{ 
    // The message loop lasts until we get a WM_QUIT message,
    // upon which we shall return from the function.
    while (TRUE)
    {
        // block-local variable 
        DWORD result ; 
        MSG msg ; 

        // Read all of the messages in this next loop, 
        // removing each message as we read it.
        while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) 
        { 
            // If it is a quit message, exit.
            if (msg.message == WM_QUIT)  
                return 1; 
            // Otherwise, dispatch the message.
            DispatchMessage(&msg); 
        } // End of PeekMessage while loop.

        // Wait for any message sent or posted to this queue 
        // or for one of the passed handles be set to signaled.
        result = MsgWaitForMultipleObjects(cObjects, lphObjects, 
                 FALSE, INFINITE, QS_ALLINPUT); 

        // The result tells us the type of event we have.
        if (result == (WAIT_OBJECT_0 + cObjects))
        {
            // New messages have arrived. 
            // Continue to the top of the always while loop to 
            // dispatch them and resume waiting.
            continue;
        } 
        else 
        { 
            // One of the handles became signaled. 
            DoStuff (result - WAIT_OBJECT_0) ; 
        } // End of else clause.
    } // End of the always while loop. 
} // End of function.

Можно создать WaitableTimer на 15 секунд например и передать его в эту функцию -
MessageLoop(&hTimer, 1); и она будет крутить цикл сообщений пока не пройдет 15 секунд (правда тогда "DoStuff (result - WAIT_OBJECT_0) ;" надо на "return" наверно заменить )
BBB
Сообщения: 1272
Зарегистрирован: 27 дек 2005, 13:37

25 сен 2007, 11:57

WinMain писал(а):Удобнее использовать не голые Win32API-функции, а применить класс-обёртку на С++. Набери в поисковике что-нибудь типа "CWaitableTimer".
WinMain, Hawk,
я вот тоже, глядя на найденные примеры (как в MSDN, так и в интернете), вижу, что после запуска таймера тем или иным способом запускается "остановка (ожидание)" в денной точке. Без этого, похоже, не будет вызванна указанная callback-процедура. (Кстати, в большинство примеров вызов SetWaitableTimer происходит без указания callback-процедуры).

Например, в одном из примеров (MFC-dialog-based-приложения) таймер запускается при нажатии на кнопку окна. Т.е., стало быть (если копать "вглубь"), внутри оконной пр-ры-обработчика событий. И далее тут же стоит:

SleepEx (INFINITE, TRUE);

Callback-функция (указанная в SetWaitableTimer) вызывается, после чего SleepEx возвращает управление.

Убираю этот SleepEx (т.е. получаем, что программа покидает оконную пр-ру-обработчик до истечения указанного таймеру времени) - callback-пр-ра уже не вызывается!
Hawk
Сообщения: 215
Зарегистрирован: 17 фев 2004, 14:52
Откуда: СПб
Контактная информация:

25 сен 2007, 12:10

А тебе так нужен callback? Исходя из твоей задачи он тебе не нужен совсем. А callback можно сделать и обычным SetTimer если так надо.
BBB
Сообщения: 1272
Зарегистрирован: 27 дек 2005, 13:37

25 сен 2007, 12:38

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