Поиск:

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


Новичок



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

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



Здравствуйте.
У меня наблюдается чрезвычайно странный глюк.
Вот простейший код в Билдере (форма с таймером):

Код

static DWORD TStart=GetTickCount();
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
  Canvas->TextOut(0,0, ::GetTickCount() - TStart );
}
//---------------------------------------------------------------------------


Через какие-то неравные промежутки времени инкрементирование числа останавливается и висит в таком положении какие-то доли секунды, потом опять продолжается. Причем, без скачка.
Я бы мог подумать, что это виснет моя программа, но раз используется системный таймер, то, получается, это он тормозит. Т.е. у меня весь компьютер виснет на какие-то доли секунды вместе с системным таймером (страшная вещь). Но если бы это было так, мои часы (те, что в трее) постепенно начинали бы отставать, но они идут исправно.

Подскажите, пожалуйста, в чем может быть проблема, у меня голова уже не варит.
PM MAIL   Вверх
xvr
Дата 15.5.2008, 12:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

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



На какой интервал настроен Timer1? При малых интервалах так вполне может быть

PM MAIL   Вверх
crYon
Дата 15.5.2008, 19:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Не важно, на какой. Например на 1000 или 100 мс. А почему на малых вдруг такое может быть?
PM MAIL   Вверх
xvr
Дата 15.5.2008, 19:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

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



Цитата(crYon @ 15.5.2008,  19:38)
Не важно, на какой. Например на 1000 или 100 мс. А почему на малых вдруг такое может быть?

Event'ы от таймера приходят в виде сообщений через общую очередь сообщений. Если интервал маленький или в цикле обработки сообщений есть какие то процедуры занимающие много времени, то event'ы от таймера будут накапливаться в очереди и потом отрабатываться пачками.
PM MAIL   Вверх
Artemon
Дата 16.5.2008, 06:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


а ты мне нравишься
***


Профиль
Группа: Завсегдатай
Сообщений: 1771
Регистрация: 24.2.2004
Где: Челябинск

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



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


--------------------
Контроль топлива на топливозаправщиках, мониторинг автотранспорта, расчет зарплаты водителей www.rscat.ru
PM MAIL   Вверх
mrbrooks
Дата 16.5.2008, 07:49 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


трололомен
****


Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

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



Во первых Timer не рекомендуется использовать на интервале меньше 50.
Во вторых лучше явно приводить к типу указанному в сигнатуре функции. Не стоит уповать на приведение типов Бормана по умолчанию.
Код

static DWORD TStart=GetTickCount();
//---------------------------------------------------------------------------
void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
  Canvas->TextOut(0,0, String(GetTickCount() - TStart) );
}
//---------------------------------------------------------------------------

В третьих что такого ужасного выводить данные в компонент - типа метки или statictext и забить на канву?
PM MAIL   Вверх
crYon
Дата 16.5.2008, 09:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(xvr @  15.5.2008,  19:46 Найти цитируемый пост)
event'ы от таймера будут накапливаться в очереди и потом отрабатываться пачками

сообщения WM_TIMER не будут накапливаться, т.к. они запихиваются в очередь только при отсутствии в ней других сообщений. В любом случае, это не причина моей проблемы, т.к. возобновление обработки сообщений вызывало бы скачок счетчика, а, как я уже писал, его нет.
Цитата(Artemon @  16.5.2008,  06:16 Найти цитируемый пост)
Если хотите чтобы было все ровно

И так должно быть все равно, без использования потоков и синхронизации. Ведь нет привязки к количеству вызовов обработчика таймера. Прошедшее время узнается уже в самом обработчике. А как по Вашему, если я сделаю все как Вы сказали, такого не будет? Вряд ли. Мне ведь все равно придется использовать GetTickCount (ну или GetSystemTime/GetLocalTime), а похоже, что причина именно в них.
Цитата(mrbrooks @  16.5.2008,  07:49 Найти цитируемый пост)
лучше явно приводить к типу указанному в сигнатуре функции

Абсолютно ни чем не лучше, если ты знаком со всеми ее перегруженными вариантами. В данном случае их вообще нет. Тогда уж не String, а AnsiString. И, самое интересное, кто такой Борман?
Цитата(mrbrooks @  16.5.2008,  07:49 Найти цитируемый пост)
В третьих что такого ужасного выводить данные в компонент - типа метки или statictext и забить на канву?

Абсолютно ничего ужасного. Я уже перепробовал по всякому. Причина не в этом, причина в ф-ии GetTickCount. Я не использовал лэйблоподобный контрол в примере только потому, чтобы Вам было легче воспроизвести пример.
PM MAIL   Вверх
mrbrooks
Дата 16.5.2008, 09:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


трололомен
****


Профиль
Группа: Завсегдатай
Сообщений: 4259
Регистрация: 4.10.2006
Где: Дол Гулдур

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



Борман шутливое название Борланда.
А теперь объясни мне разницу в билдере между String и AnsiString?


Это сообщение отредактировал(а) mrbrooks - 16.5.2008, 09:23
PM MAIL   Вверх
xvr
Дата 16.5.2008, 12:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

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



Цитата(crYon @ 16.5.2008,  09:09)
Цитата(xvr @  15.5.2008,  19:46 Найти цитируемый пост)
event'ы от таймера будут накапливаться в очереди и потом отрабатываться пачками

сообщения WM_TIMER не будут накапливаться, т.к. они запихиваются в очередь только при отсутствии в ней других сообщений. 

Не совсем:
Цитата

The WM_TIMER message is a low-priority message. The GetMessage and PeekMessage functions post this message only when no other higher-priority messages are in the thread's message queue. 
Т.е. WM_TIMER все же могут накапливаться.
Цитата

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

PM MAIL   Вверх
Artemon
Дата 16.5.2008, 14:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


а ты мне нравишься
***


Профиль
Группа: Завсегдатай
Сообщений: 1771
Регистрация: 24.2.2004
Где: Челябинск

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



Цитата

И так должно быть все равно, без использования потоков и синхронизации. Ведь нет привязки к количеству вызовов обработчика таймера. Прошедшее время узнается уже в самом обработчике. А как по Вашему, если я сделаю все как Вы сказали, такого не будет? Вряд ли. Мне ведь все равно придется использовать GetTickCount (ну или GetSystemTime/GetLocalTime), а похоже, что причина именно в них.


Если причина в GetTickCount то не поможет,

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


Это сообщение отредактировал(а) Artemon - 16.5.2008, 14:56


--------------------
Контроль топлива на топливозаправщиках, мониторинг автотранспорта, расчет зарплаты водителей www.rscat.ru
PM MAIL   Вверх
crYon
Дата 16.5.2008, 15:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Цитата(mrbrooks @  16.5.2008,  09:23 Найти цитируемый пост)
А теперь объясни мне разницу в билдере между String и AnsiString?

Никакой. Просто я так понял, что ты хочешь следовать сигнатуре функции.

Цитата(xvr @  16.5.2008,  12:00 Найти цитируемый пост)
Не совсем:
Цитата

The WM_TIMER message is a low-priority message. The GetMessage and PeekMessage functions post this message only when no other higher-priority messages are in the thread's message queue. 

Т.е. WM_TIMER все же могут накапливаться.


Цитата(Borland C++Builder Help)

WM_TIMER
The DispatchMessage function forwards this message when no other messages are in the thread's message queue.

А VCL использует DispatchMessage всегда. Правда эту фразу тоже можно понять двояко, что имеется в виду под "другими сообщениями" - любые сообщения, уже содержащиеся в очереди, или сообщения, отличающиеся от WM_TIMER.

Добавлено через 2 минуты и 33 секунды
Провел несколько тестов.
Результаты очень интересные.

Запустил прогу и сверял по механическому секундомеру.
После 5 минут задержка составила ~ 25 секунд.
После 10 минут задержка составила ~ 48 секунд.

Запустил два экземпляра проги (в разное время). Обе проги тормозили абсолютно синхронно. Т.е. счетчик останавливался и снова запускался в обоих прогах одновременно, хотя запущены они были в разное время. Отсюда я опять делаю вывод, что тормозят именно системные часы. Но, повторюсь, часы в трее идут исправно. Стало быть, они используют другие механизмы, отличные от вызовов GetTickCount/GetSystemTime/GetLocalTime.
Все никак не могу проверить на другом компьютере. Кто-нибудь проверял данный код? Ни у кого больше задержки не было?

Я либо скоро стану идиотом, либо поверю в колдовство, либо раскрою страшный баг Windows. Или это будет баг Матрицы. А может это будет парадокс, который повлечет за собой цепную реакцию и разрушение вселенной...
PM MAIL   Вверх
crYon
Дата 16.5.2008, 20:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



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

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



Попробовал без использования VCL, на WinAPI.


Код

//---------------------------------------------------------------------------
#include <windows.h>
#include <stdio.h>
//---------------------------------------------------------------------------

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam);

WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX WndClassEx;
  WndClassEx.cbSize          = sizeof(WNDCLASSEX);
  WndClassEx.style           = CS_HREDRAW | CS_VREDRAW;
  WndClassEx.lpfnWndProc     = WndProc;
  WndClassEx.cbClsExtra      = 0;
  WndClassEx.cbWndExtra      = 0;
  WndClassEx.hInstance       = hInstance;
  WndClassEx.hIcon           = LoadIcon(NULL, IDI_QUESTION);
  WndClassEx.hCursor         = LoadCursor(NULL, IDC_ARROW);
  WndClassEx.hbrBackground   = (HBRUSH)COLOR_WINDOW;
  WndClassEx.lpszMenuName    = NULL;
  WndClassEx.lpszClassName   = "XXXWindow";
  WndClassEx.hIconSm      = LoadIcon(NULL, IDI_QUESTION);
  if(!RegisterClassEx(&WndClassEx)) return -1;
  HWND FMain = CreateWindow("XXXWindow", "Weird thing", WS_OVERLAPPEDWINDOW,
               CW_USEDEFAULT, 0, 200, 80, NULL, NULL, hInstance, NULL);
  if(FMain == NULL) return -1;
  ShowWindow(FMain, SW_SHOW);
  UpdateWindow(FMain);

  SetTimer(FMain, 1, 100, NULL);

  MSG  msg;
  int status;
  while ((status = GetMessage(&msg, 0, 0, 0)) != 0)
  {
    if (status == -1) return status;
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}
//---------------------------------------------------------------------------
LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
  volatile static DWORD Count = 0, TStart = GetTickCount();

  switch(Message)
  {
    case WM_CREATE:
      return 0;
    case WM_TIMER:
    {
      static char Message[100];
      sprintf(Message,"count = %d, dt = %d",++Count,GetTickCount()-TStart);
      HDC hdc = GetDC(hwnd);
      TextOut(hdc,0,0,Message,strlen(Message));
      ReleaseDC(hwnd,hdc);
      break;
    }
    case WM_CLOSE:
      DestroyWindow(hwnd);
      KillTimer(hwnd,1);
      return 0;
    case WM_DESTROY:
      PostQuitMessage(0);
      return FALSE;
  }
  return DefWindowProc(hwnd, Message, wParam, lParam);
}
//---------------------------------------------------------------------------



Та же самая история... 

PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++ Builder"
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по С++ Builder обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Настоятельно рекомендуем заглянуть в DRKB (Delphi Russian Knowledge Base) - крупнейший в рунете сборник материалов по Дельфи


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

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


 




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


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

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