Safe Win32 Timer
От: Приходько Михаил aka Crusader Mike Беларусь  
Дата: 15.08.01 10:13
Оценка: 1 (1)
Статья:
Safe Win32 Timer
Автор(ы): Приходько Михаил aka Crusader Mike


Авторы:
Приходько Михаил aka Crusader Mike

Аннотация:
этот класс является источников "безопасных" таймерных нотификаций. Т.е. он не обладает гениальным недостатком обычного таймера, который оставляет WM_TIMER сообщения в очереди после вызова KillTimer. Этот класс должен быть использован и удален только из потока, т.к. он создает и использует окошко.
Поддерживаю идею насчёт multimedia timers
От: Smart Россия  
Дата: 11.05.02 00:35
Оценка: 1 (1)
multimedia timers намного быстрее (плавное перемещение несколких Common Controls с перерисовкой на iP-200:-) под WinXP:-0 с включёнными Visual Styles 8-) выдаёт 30~40fps, приоритет процесса и потока — Normal) и точнее (разрешение 5 ms — не тормозит и вполне достаточно для UI), а использование почти ничем не отличается от использования тормозных сообщений WM_TIMER, толко вместо обработки WM_TIMER нужно написать callback функцию.
Может multimedia timers?
От: Блудов Павел Россия  
Дата: 26.08.01 20:01
Оценка:
timeSetEvent() есть даже в Win95. Или он тоже не настоящий?
CreateWaitableTimer только под NT!
От: Курилка Россия http://kirya.narod.ru/
Дата: 19.08.01 23:15
Оценка:
но CreateWaitableTimer тоже только под NT работает
WM_TIMER нестабилен
От: Аноним  
Дата: 16.08.01 10:13
Оценка:
таймер создаваемый функцией CreateTimer вообще по своей природе не стабилен (это не таймер а вообще хрень какято) так как он эмулируется из настоящих таймеров ядра подсистемой User32. Которая стоит в данном случае над ядром. Именно по этому я отказался от использования данного таймера в серъезных целях. Да еще и к томуже способ сообщения т.е. посылка события оставляет желать лучшего. Вместо этого я бы вам предложил посмотреть функцию CreateWaitableTimer которая предостовляет реальные таймеры (ну почти), ну а если мы пишем под NT(2000) то весьма целесообразно будет использовать функции NtCreateTimer,NtSetTimer,NtCancelTimer,NtOpenTimer представленные в NtDll.dll (но к сожалению не документированые).
С Уважением Mr.Orbit <mrorbit@mail.ru>
Re: CreateWaitableTimer только под NT!
От: Ktirf  
Дата: 23.08.01 22:22
Оценка:
А FlushInstructionCache под 9x есть, но ничего не делает. IMHO, этот код писался не для 9x все-таки.

А касаемо способа работы с таймерами, есть такая идея. Во-первых, пусть это каждый решает для себя, в меру своей крутости, понтов и т.п. А во-вторых, чтобы это можно было реализовать, делается следующее: из CTimerHost выдирается весь специфический код (то есть большая часть SetTimer, большая часть KillTimer, m_hWnd и тот самый PostMessage, который, видимо, не понравился Анониму) и помещается в CReceiver. Дальше на совести использующего лежит написание такого CReceiver, который ему нужен (можно сделать иерархию с интерфейсом, скажем, IReceiver, в корне). А CTimerHost переделывается в шаблон, параметром в котором выступает этот самый CReceiver. Дальше там, где стояли определения переменных CTimerHost, мы ставим определения CTimerHost<CMyReceiver> и радуемся жизни.
Re:CreateWaitableTimer только под NT!
От: Alexander Shargin Россия RSDN.ru
Дата: 20.08.01 00:58
Оценка:
И под Win98. А под Win95 — нету...
--
Я думал, ты огромный страшный Бажище,
А ты недоучка, крохотный Бажик...
Re: Safe Win32 Timer
От: CoolCmd Россия  
Дата: 27.08.08 15:50
Оценка:
Здравствуйте, Приходько Михаил aka Crusader Mike, Вы писали:

ПМA>этот класс является источников "безопасных" таймерных нотификаций. Т.е. он не обладает гениальным недостатком обычного таймера, который оставляет WM_TIMER сообщения в очереди после вызова KillTimer. Этот класс должен быть использован и удален только из потока, т.к. он создает и использует окошко.

Чет слишком сложный таймер у автора получился. Предлагаю более простой вариант без создания окон, использования MFC, объектов (не люлю я их), фанков и прочих жутких вещей. Смысл предлагаемого метода — для одного таймера использовать несколько идентификаторов, которые при удалении таймера сменяют друг друга. Таким образом застрявшее в очереди сообщение WM_TIMER (в 99.99% случаев оно будет одно) не будет иметь текущий идентификатор и, следовательно, не будет обработано. Заодно (бонус! ) реализуется проверка на такую неприятную в большинстве случаев вещь, как рекурсивный вызов обработчика таймера (я думаю, все видели проги, генерящие по таймеру кучу одинаковых сообщений об ошибке ).

Единственное пояснение. В случае необходимости можно переопределить SAFE_TIMER_ID_BITS. Оно определяет количество битов для идентификаторов таймера. 1 бит = 2 идентификатора, 2 бита = 4 идентификатора и т.д. В большинстве случаев хватит 1 бита, а ситуацию когда не хватит трех с трудом могу представить. Это наверное будет плохо спроектированное приложение.

// SafeTimer.h
#pragma once

#ifndef SAFE_TIMER_ID_BITS
#define SAFE_TIMER_ID_BITS 1
#endif

#define SAFE_TIMER_ID_MASK  UINT_PTR(((1 << (SAFE_TIMER_ID_BITS)) - 1) << 1)
#define SAFE_TIMER_BUSY_BIT UINT_PTR(1)

DECLARE_HANDLE(SAFE_TIMER);

inline SAFE_TIMER InitSafeTimer(UINT_PTR uTimerId)
{
    return SAFE_TIMER(uTimerId << ((SAFE_TIMER_ID_BITS) + 1));
}

inline bool IsSafeTimerId(SAFE_TIMER SafeTimer, WPARAM wParam)
{
    return (UINT_PTR(SafeTimer) & ~SAFE_TIMER_BUSY_BIT) == UINT_PTR(wParam);
}

inline bool IsSafeTimerFunctionBusy(SAFE_TIMER *pSafeTimer)
{
    if (*PUINT_PTR(pSafeTimer) & SAFE_TIMER_BUSY_BIT)
    {
        return true;
    }
    *PUINT_PTR(pSafeTimer) |= SAFE_TIMER_BUSY_BIT;
    return false;
}

inline void SafeTimerFunctionComplete(SAFE_TIMER *pSafeTimer)
{
    *PUINT_PTR(pSafeTimer) &= ~SAFE_TIMER_BUSY_BIT;
}

inline UINT_PTR SetSafeTimer(HWND hWnd, SAFE_TIMER SafeTimer, UINT uElapse, TIMERPROC lpTimerFunc)
{
    _ASSERT(hWnd != NULL);
    return SetTimer(hWnd, UINT_PTR(SafeTimer) & ~SAFE_TIMER_BUSY_BIT, uElapse, lpTimerFunc);
}

inline BOOL KillSafeTimer(HWND hWnd, SAFE_TIMER *pSafeTimer)
{
    BOOL b = KillTimer(hWnd, *PUINT_PTR(pSafeTimer) & ~SAFE_TIMER_BUSY_BIT);
#if (SAFE_TIMER_ID_BITS) == 1
    *PUINT_PTR(pSafeTimer) ^= 2;
#else
    *PUINT_PTR(pSafeTimer) = ((*PUINT_PTR(pSafeTimer) + 2) & SAFE_TIMER_ID_MASK)
        | (*PUINT_PTR(pSafeTimer) & ~SAFE_TIMER_ID_MASK);
#endif
    return b;
}

#undef SAFE_TIMER_ID_BITS
#undef SAFE_TIMER_ID_MASK
#undef SAFE_TIMER_BUSY_BIT


Пример использования в оконной процедуре:
const UINT_PTR IDR_DIALOG_UPDATE    = 1;
const UINT_PTR IDR_UNINST_WIN_PISTA = 2;
const UINT_PTR IDR_KILL_S_BALMER    = 3;
.
.
SAFE_TIMER m_stDialogUpdate = InitSafeTimer(IDR_DIALOG_UPDATE);
.
.
SetSafeTimer(hwndDlg, m_stDialogUpdate, DIALOG_UPDATE_FREQUENCY, 0);
.
.
KillSafeTimer(hwndDlg, &m_stDialogUpdate);
.
.
case WM_TIMER:
    if (IsSafeTimerId(m_stDialogUpdate, wParam))
    {
        if (!IsSafeTimerFunctionBusy(&m_stDialogUpdate))
        {
            // ...
            SafeTimerFunctionComplete(&m_stDialogUpdate);
        }
        return TRUE;
    }
    break;


Пример использования в функции:
const UINT_PTR IDR_DIALOG_UPDATE    = 1;
const UINT_PTR IDR_UNINST_WIN_PISTA = 2;
const UINT_PTR IDR_KILL_S_BALMER    = 3;
.
.
SAFE_TIMER m_stDialogUpdate = InitSafeTimer(IDR_DIALOG_UPDATE);
.
.
SetSafeTimer(hwndDlg, m_stDialogUpdate, DIALOG_UPDATE_FREQUENCY, OnDialogUpdate);
.
.
KillSafeTimer(hwndDlg, &m_stDialogUpdate);
.
.
void CALLBACK OnDialogUpdate(HWND, UINT, UINT_PTR, DWORD)
{
    if (IsSafeTimerFunctionBusy(&m_stDialogUpdate))
    {
        return;
    }
    // ...
    SafeTimerFunctionComplete(&m_stDialogUpdate);
}
простите, я убил небо
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.