Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Событие WM_TIMER, Ускорить работу таймера 
:(
    Опции темы
Дрон
Дата 1.7.2004, 22:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java-ненавистник :)
****


Профиль
Группа: Участник Клуба
Сообщений: 3179
Регистрация: 29.12.2002
Где: Санкт-Петербург

Репутация: 10
Всего: 92



gepard
Да, эта функция есть только в VC++ .NET. И точность у неё около 16мс.
GetTickCount() тоже даёт точность только ~16мс exclamation.gif
Можете проверить сами, записывая в файл в цикле значения, полученные из этих функций.

Я уже с этим не раз сталкивался -- в Windows ничего особо толкового не получится.
Миллион раз уже тут писал, что нужно пользоваться QueryPerformanceCounter -- поищите по форуму.

Самый примитивный способ, использующий эту функцию:
Цитата
    LARGE_INTEGER interval,start,now;
    QueryPerformanceFrequency(&interval);
    interval.QuadPart *= 0.003;

    QueryPerformanceCounter(&start);
    do{
          QueryPerformanceCounter(&now);
    }while (now.QuadPart - start.QuadPart <= interval.QuadPart);

Цикл закончится, когда пройдёт интервал в 0.003 секунды -- с точностью до скорости выполнения команды.
Недостаток -- грузит проц на 100% для больших интервалов.

Это сообщение отредактировал(а) Дрон - 2.7.2004, 05:46


--------------------
Да. Именно так.
PM   Вверх
bel_nikita
  Дата 1.7.2004, 23:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Эксперт
Сообщений: 2304
Регистрация: 12.10.2003
Где: Поезд №21/22 ( ст . Прага )

Репутация: 21
Всего: 47



Цитата
GetTickCount() тоже даёт точность только ~16мс
Можете проверить сами, записывая в файл в цикле значения, полученные из этих функций

запись в файл не показатель. В цикле писать в файл и потом удивляться, что GetTickCount() выдает сумашедшие результаты . Оригинально biggrin.gif . ~16мс, грубо говоря, в таком случае, получается время записи в файл не считая thread'ы и т.п. Вообще-то GetTickCount() даёт точность 1мс biggrin.gif .

В винде, как знаю еще есть CreateWaitableTimer. Только не знаю она его в нулевой интерапт встраивает или нет. И как запрограммирован таймер в винде?

Это сообщение отредактировал(а) bel_nikita - 2.7.2004, 00:04


--------------------
user posted image — регистрация доменов от 150 руб.
PM MAIL WWW ICQ   Вверх
Дрон
Дата 2.7.2004, 01:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java-ненавистник :)
****


Профиль
Группа: Участник Клуба
Сообщений: 3179
Регистрация: 29.12.2002
Где: Санкт-Петербург

Репутация: 10
Всего: 92



bel_nikita
Ты не правильно меня понял smile.gif
Результаты записи в файл были примерно такие:
Цитата
0
0
0
... и так несколько сотен раз
15
15
15
... и так несколько сотен раз
30
30
30
... и так несколько сотен раз

За эти 15мс прога успевала записать строку в файл "несколько сотен раз" smile.gif

Если не веришь, то вот другой простой тест:
Цитата
#include <windows.h>
#include <stdio.h>
#include <math.h>

#define ARRSIZE 2000 // не более 2х секунд, иначе нужно увеличить

void main()
{
    float z = 1233;
    const N = 100000;
    int vals[ARRSIZE];
    int i,k;
    ZeroMemory(vals,sizeof(int)*ARRSIZE);
    for(k=0;k<100;k++){
          DWORD start = GetTickCount();
          for(i=0; i<N; i++)
          {
              z = exp(log(z));
          }
          DWORD finish = GetTickCount();
          vals[finish-start]++;
    }
    FILE *fp = fopen("results.txt","wt");
    for(i=0;i<ARRSIZE;i++)
    {
          if(vals[i]!=0) fprintf(fp,"%i мс: %i%%\n",i,vals[i]);
    }
    fclose(fp);
}

Тут зависит от быстродействия компа. Уменя Athlon XP 2500+.
Результаты
При N = 100000 - 15 мс: 24%, 16 мс: 35%, 31 мс: 29%, 32 мс: 12%
При N = 50000 - 0 мс: 29%, 15 мс: 26%, 16 мс: 45%
При N = 25000 - 0 мс: 64%, 15 мс: 14%, 16 мс: 22%
Я знал, что AMD делает крутые процессоры, но то что они в 64% случаях могут вычислить 25000 сложных математических операций вообще не потратив на это времени -- это уже действительно круто! smile.gif smile.gif smile.gif

WaitableTimer может быть и полезен. Как и Sleep smile.gif
Только на любой из методов будут очень сильно влиять другие процессы и потоки.

ЗЫ: Подсветка синтаксиса моя -- экспериментальная smile.gif

Это сообщение отредактировал(а) Дрон - 2.7.2004, 05:48


--------------------
Да. Именно так.
PM   Вверх
bel_nikita
Дата 2.7.2004, 09:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Эксперт
Сообщений: 2304
Регистрация: 12.10.2003
Где: Поезд №21/22 ( ст . Прага )

Репутация: 21
Всего: 47



Дрон - это совсем не то. Это замер времени выполнения. Причем грубый и не отражающий реальное быстродействие процессора. А не задумывались, сколько раз во время цикла происходят переключения на другие thread'ы?. Что-то я отвлекся smile.gif Надо-то ведь таймер.



--------------------
user posted image — регистрация доменов от 150 руб.
PM MAIL WWW ICQ   Вверх
kruchinin
Дата 2.7.2004, 09:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 19.4.2003

Репутация: нет
Всего: нет



Почитайте обычный help Borlandа 5.0
Стандартные функции
GetTickCount
или
QueryPerformanceCounter, QueryPerformanceFrequency

я не понимаю какие могут быть проблемы - эти функции работают с частотой процессора.

PM MAIL   Вверх
bel_nikita
Дата 2.7.2004, 10:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Эксперт
Сообщений: 2304
Регистрация: 12.10.2003
Где: Поезд №21/22 ( ст . Прага )

Репутация: 21
Всего: 47



kruchinin
Цитата
я не понимаю какие могут быть проблемы - эти функции работают с частотой процессора
проблема реализовать таймер с частотой <3ms wink.gif biggrin.gif
Цитата
Почитайте обычный help Borlandа 5.0

Мы люди темные. Help'ы к борланду не читали.
Если у вас все так просто, привидите пожалуйста пример реализации таймера под Виндой, который будет срабатывать менее чем 3мсек biggrin.gif


--------------------
user posted image — регистрация доменов от 150 руб.
PM MAIL WWW ICQ   Вверх
Олег М
Дата 2.7.2004, 10:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 436
Регистрация: 10.6.2004
Где: Москва

Репутация: 7
Всего: 7



Цитата
Мы люди темные. Help'ы к борланду не читали.

А как насчёт мсдн?
Цитата
Если у вас все так просто, привидите пожалуйста пример реализации таймера под Виндой, который будет срабатывать менее чем 3мсек 

К сожалению пока не могу, но так, теоретически, по моему в виндах процессы переключаются намного чаще чем раз в 1 мс. Почему бы нет?

PM MAIL ICQ   Вверх
kruchinin
Дата 2.7.2004, 11:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 100
Регистрация: 19.4.2003

Репутация: нет
Всего: нет



Вот код из моей игры Танки 3:
system_a=true;//переменная для выхода из системы
// в игре я не посылаю сообщение WM_QUIT, а просто меняю переменную
freg1=GetTickCount();
for_fps=0;//вычисление FPS
tick=false;//произошло ли событие таймера
while (true)
{
//обработка сообщений
if (PeekMessage(&Msg,NULL,0,0,PM_REMOVE))
{
if (Msg.message == WM_QUIT)
break;
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
else ;
//вызов таймера
if (system_a)
{
if (tick) {//если нужное время прошли - рисуем картинки
None(hWnd);
tick=false;
}
freg2=GetTickCount();
if (freg2-freg1>1000/_TIMER_)
{//определяем нужное время _TIMER_ - задать это время
tick=true;
for(i=freg2-freg1;i>1000/_TIMER_;i-=1000/_TIMER_)
{
for(j=0;j<_TIMER_-1;j++) fps_a[j]=fps_a[j+1];
fps_a[_TIMER_-1]=for_fps;//ну это не важно просто для измерения FPS в игре
for_fps=0;
fps=0;
for(j=0;j<_TIMER_;j++) fps+=fps_a[j];
OnTimer(hWnd);//вызываем событие таймера
}
freg1=GetTickCount()-i;
//выход из игры
if (Exit_Game) PostMessage(hWnd,WM_DESTROY,0,0);
}
}
}

PM MAIL   Вверх
Олег М
Дата 2.7.2004, 12:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 436
Регистрация: 10.6.2004
Где: Москва

Репутация: 7
Всего: 7



Танки - это круто adv/64.gif
PM MAIL ICQ   Вверх
Дрон
Дата 2.7.2004, 14:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java-ненавистник :)
****


Профиль
Группа: Участник Клуба
Сообщений: 3179
Регистрация: 29.12.2002
Где: Санкт-Петербург

Репутация: 10
Всего: 92



Цитата
Дрон - это совсем не то. Это замер времени выполнения. Причем грубый и не отражающий реальное быстродействие процессора.
Да я тут не быстродействие меряю! А показываю, что функция GetTickCount() имеет предел точности в 16мс!!!!

Ну ладно. Забили smile.gif
Раз нужен таймер -- получайте (работает только в Windows NT/2K/XP, т.к. в 95/98/Me нет функции CreateWaitableTimer()):
Цитата
#define _WIN32_WINNT 0x0400
#include <windows.h>

#include <stdio.h>
#include <conio.h>

// ------------------------------------------------------------------------------

class WaitableTimer{
    HANDLE hTerminationEvent; // сигнал к завершению потока
    HANDLE hThread; // хэндл потока с таймером
    int  nPeriod; // период таймера
    void (APIENTRY *pRoutine)(LPVOID,DWORD,DWORD); // функция, вызываемая по таймеру
    static DWORD WINAPI TimerThread(LPVOID Param); // функция потока
public:
    // конструктор: nMillisec - период таймера, pTimerRoutine - указатель на вызываемую функцию
    WaitableTimer(int nMillisec, void (APIENTRY *pTimerRoutine)(LPVOID,DWORD,DWORD));
    ~WaitableTimer();
    void Stop()  { SuspendThread(hThread); } // приостанавливает таймер
    void Start() { ResumeThread(hThread)} // запускает таймер
};

WaitableTimer::WaitableTimer(int nMillisec, void (APIENTRY *pTimerRoutine)(LPVOID,DWORD,DWORD))
{
    DWORD Id;
    nPeriod = nMillisec;
    pRoutine = pTimerRoutine;
    hTerminationEvent = CreateEvent(NULL,false,false,NULL);
    hThread = CreateThread(NULL,0,TimerThread,this,CREATE_SUSPENDED,&Id);
}

WaitableTimer::~WaitableTimer()
{
    SetEvent(hTerminationEvent);
    WaitForSingleObject(hThread,nPeriod);
    CloseHandle(hTerminationEvent);
    CloseHandle(hThread);
}

DWORD WINAPI WaitableTimer::TimerThread(LPVOID Param)
{
    // можно попробовать поиграть с приоритетами -- это уже на ваше усмотрение
    // SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL);
    WaitableTimer *obj = (WaitableTimer*)Param;
    LARGE_INTEGER DueTime;
    DueTime.QuadPart = -10000i64 * obj->nPeriod;
    HANDLE hTimer = CreateWaitableTimer(NULL,false,NULL);
    SetWaitableTimer(hTimer,&DueTime,obj->nPeriod,obj->pRoutine,obj,false);
    while (WaitForSingleObjectEx(obj->hTerminationEvent,INFINITE,true)==WAIT_IO_COMPLETION);
    CloseHandle(hTimer);
    return 0;
}

// ------------------------------------------------------------------------------

int i=0;
// первый параметр -- указатель на класс таймера (типа void)
void APIENTRY MyTimerRoutine(LPVOID lpArgToCompletionRoutine,
                            DWORD dwTimerLowValue,
                            DWORD dwTimerHighValue)
{
    i++;
}

// ------------------------------------------------------------------------------

void main()
{
    WaitableTimer Timer(4,MyTimerRoutine); // создали таймер на 4мс
    Timer.Start(); // запустили его (т.к. создаётся остановленным)
    Sleep(1000); // подождали 1 секунду
    printf("\n%i\n",i); // вывели количество запусков функции MyTimerRoutine
    getch(); // нажмите любую клавишу :-)
}
На моём компе выдаёт результат 204, вместо ожидаемых 250. А с периодом 3мс выдаёт 256, вместо 330.
Ничего более хорошего тут уже ИМХО не добиться.

Это сообщение отредактировал(а) Дрон - 2.7.2004, 17:37


--------------------
Да. Именно так.
PM   Вверх
Олег М
Дата 6.7.2004, 11:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 436
Регистрация: 10.6.2004
Где: Москва

Репутация: 7
Всего: 7



Цитата
На моём компе выдаёт результат 204, вместо ожидаемых 250. А с периодом 3мс выдаёт 256, вместо 330.

Ну а как ты хотел. Другим потокам-то тоже нужно время чтобы переключаться и работать - на забывай винды нифига не система реального времени. Вот и получается меньше. Вот если бы больше!!!!
А цифры такие же остаются или скачут постоянно?

PM MAIL ICQ   Вверх
Дрон
Дата 6.7.2004, 12:15 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Java-ненавистник :)
****


Профиль
Группа: Участник Клуба
Сообщений: 3179
Регистрация: 29.12.2002
Где: Санкт-Петербург

Репутация: 10
Всего: 92



Цитата
Ну а как ты хотел. Другим потокам-то тоже нужно время чтобы переключаться и работать - на забывай винды нифига не система реального времени.

Никак не хотел. Я всё это давно знаю smile.gif

Цифры такие же плюс-минус 1. Тяжёлых фоновых приложений не было -- иначе б скакали smile.gif


--------------------
Да. Именно так.
PM   Вверх
Олег М
Дата 6.7.2004, 12:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 436
Регистрация: 10.6.2004
Где: Москва

Репутация: 7
Всего: 7



Дрон
Тогда всё нормально. Надо подсчитать чистое время, которое выполняется твой поток и всё наверняка сойдётся

PM MAIL ICQ   Вверх
zss
Дата 6.7.2004, 12:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 708
Регистрация: 17.6.2004

Репутация: 1
Всего: 2



К примеру (а если еще это в отдельный поток - то тогда то что надо smile.gif )

Причем этот код не зависит от производительности процессора tounge.gif

Цитата

Для работы с таймером (точнее говоря, для работы с каналом 0 таймера) BIOS содержит две функции прерывания INT 1Ah. Они позволяют прочитать текущее содержимое счетчика и изменить его.

Функция 00h предназначена для чтения содержимого счетчика таймера:

На входе:      AH = 00h.

На выходе:      CX = старший байт счетчика;

                DX = младший байт счетчика;

                AL = 0, если с момента перезапуска таймера
                        прошло более 24-х часов.



Изменить содержимое счетчика таймера можно с помощью следующей функции:

На входе:      AH = 01h;

                CX = старший байт счетчика;

                DX = младший байт счетчика.

На выходе:      не используются.



Функцию чтения таймера можно использовать для организации программной задержки. Так как работа таймера не зависит от производительности процессора, быстродействие системы не будет влиять на формируемую задержку.

Однако следует учитывать, что точность формирования задержки определяется частотой обновления счетчика таймера (18.2 Гц), и может оказаться недостаточной для некоторых приложений.

Мы подготовили функцию для формирования задержек с помощью таймера:

/**
*.Name        tm_delay
*.Title        Формирование задержки по таймеру
*
*.Descr        Эта функция формирует задержку, используя
*              системный таймер.
*
*.Proto        void tm_delay(int ticks)
*
*.Params      int ticks - величина задержки в тиках
*                          таймера (за одну секунду таймер
*                          тикает 18.2 раза).
*
*.Return      Ничего
*
*.Sample      tm_samp1.c
**/

#include <dos.h>
#include <conio.h>

void tm_delay(int ticks) {

        _asm {

                push si

                mov  si, ticks
                mov  ah, 0
                int  1ah

                mov  bx, dx
                add  bx, si

delay_loop:

                int  1ah
                cmp  dx, bx
                jne  delay_loop

                pop  si
        }
}



Функция использует только одно слово регистра таймера, что позволяет формировать задержки длительностью до 65536 тиков таймера. Приведенная ниже программа демонстрирует использование функции для генерации примерно десятисекундной задержки :

#include <stdio.h>
#include "sysp.h"


main() {

        printf("\nДля выполнения программной задержки примерно"
                        "\nна 10 секунд нажмите любую клавишу.");
        getch();

        printf("\n\nВремя пошло...");

        tm_delay(18 * 10);

        printf("\nГотово!");

        exit(0);
}



BIOS компьютеров IBM AT содержит еще две интересные функции для работы с таймером. Это функции 83h и 86h прерывания INT 15h.

Функция 83h позволяет запустить таймер на счет, указав адрес некоторого байта в оперативной памяти. Программа, запустившая таймер, сразу после запуска получает управление. По истечении времени, заданного при запуске таймера, функция устанавливает старший бит указанного байта в единицу, сигнализируя таким образом программе о завершении указанного временного интервала. Программа может также отменить работу таймера в этом режиме.

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

Приведем формат вызова функции 83h прерывания INT 15h:

На входе:      AH = 83h;

                AL = код подфункции:

                  0 - установить интервал, запустить таймер;
                  1 - отменить работу таймера;

                CX = старший байт времени работы счетчика,
                  задается в микросекундах;

                DX = младший байт счетчика;

                ES:BX = адрес байта, в котором по истечении
                  интервала времени старший бит будет
                  установлен в 1.

На выходе:      не используются.



Функция 86h специально предназначена для формирования задержек. Она позволяет определять время задержки в микросекундах, что достаточно удобно для многих задач. Во время выполнения задержки разрешены прерывания. Формат вызова функции:

На входе:      AH = 86h;

        CX = старший байт времени задержки,
                задается в микросекундах;

        DX = младший байт времени задержки.

На выходе:      не используются.



Это сообщение отредактировал(а) zss - 6.7.2004, 12:30
PM MAIL ICQ   Вверх
Олег М
Дата 6.7.2004, 12:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 436
Регистрация: 10.6.2004
Где: Москва

Репутация: 7
Всего: 7



Нифига себе! Это ещё круче танков!
PM MAIL ICQ   Вверх
Страницы: (4) Все 1 [2] 3 4 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1152 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.