Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Delphi программирование > Общие вопросы Delphi
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 10.11.2010, 20:38   #1
Alex Cones
Trust no one.
Старожил
 
Аватар для Alex Cones
 
Регистрация: 07.04.2009
Сообщений: 6,526
По умолчанию Менеджер таймеров

Ситуация:

Для двига делаю возможность созания таймера средствами самого двига.
Код:
 Function CreateTimer(Freq : Integer; Proc : TSimplyProcedure) : Integer;
TSimplyProcedure - это процедура без параметров.
Так вот, как особо продвинутые из Вас знают, способов создания таймера два:

1) Через получение формой сообщения WM_TIMER.
2) Через callback функцию.

Первый способ мне не подходит по одной простой причине:
Цитата:
Заметим, что сообщение WM_TIMER является низкоприоритетным. Это означает, что функция DispatchMessage посылает это сообщение приложению только в том случае, если в очереди приложения нет других сообщений. В этом отличие таймера Windows от аналогичных средств MS-DOS, реализованных с помощью перехвата прерывания INT 8h.
Если я (пользователь) буду банально вертеть мышью - до таймера дело так и не дойдет.

А вот со вторым заковырка.

Код:
 Function CreateTimer(Freq : Integer; Proc : TSimplyProcedure) : Integer;
Пользователь дает мне просто процедуру без параметров. Запихнуть её на место каллбачной в SetTimer просто так нельзя - несоответствие типов и памяти. Хотя такой вариант тоже в принципе (теоретически, через большой геморрой) тоже можно организовать.

Обсудив этот вопрос по аське со Stilet`ом пришли к выводу, что наиболее простым и работающим вариантом будет создание потока и передача ему в параметрах процедуры, переданной пользователем, а всамо потоке создать callback, в котором вызывать пользовательскую...

НО!

Сейчас dll двигла весит 42 кб в непожатом и 21 в пожатом состояниях. Номально и даже превосходно для двигла для создания окон на WinAPI. А вот при подключении Classes для созания потоков размер уходит в 200 кб, что не приемлемо для проекта такого рода.

Что предложите, господа присяжные заседатели?
SQUARY PROJECT - НАБОР БЕСПЛАТНЫХ ПРОГРАММ ДЛЯ РАБОЧЕГО СТОЛА.
МОЙ БЛОГ
GRAY FUR FRAMEWORK - УДОБНАЯ И БЫСТРАЯ РАЗРАБОТКА WINAPI ПРИЛОЖЕНИЙ
Alex Cones вне форума Ответить с цитированием
Старый 10.11.2010, 21:02   #2
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

ну я вижу два выхода:
1)потоки на АПИ.
2)сделать список/массив соответствия ID->обработчик
Код:
ListEntry=record 
 ID:integer; 
 Proc:TSimplyProcedure;  
end; 
 
//список сам организуешь:)

далее делаем так 
procedure TimerHandler(H:THandle;uMsg:UINT;ID:UINT;Time:DWORD);stdcall;
begin
 TimerList[ID].Proc();//вроде так можно, но в общем намек понял, что нужно с нашего списка по идентификатору получить процедуру.
end;

Function CreateTimer(Freq : Integer; Proc : TSimplyProcedure) : Integer;
begin 
 Result:=TimerList.Add(SetTimer(0,0,Frec,TimerHandler),Proc);  
end;

Procedure DestroyTimer(ID:Integer);
begin 
 KillTimer(TimerList[ID].ID);
 TimerList.Delete(ID);
end;
примерно так, хотя есть проблемка синхронизации...по крайней мере может возникнуть, хотя, таймер все равно выполняется в главном потоке(тот поток что имеет цикл сообщений, он и создает обычно таймер)
кстати смотри, что работе этому таймеру в любом случае нужен цикл основной(сообщений)
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 10.11.2010, 21:14   #3
Alex Cones
Trust no one.
Старожил
 
Аватар для Alex Cones
 
Регистрация: 07.04.2009
Сообщений: 6,526
По умолчанию

Эм... Немного не понял...

Если пользователь создаст первый таймер с частотой 300 и второй с частотой 500, когда будет вызываться TimerHandler?
SQUARY PROJECT - НАБОР БЕСПЛАТНЫХ ПРОГРАММ ДЛЯ РАБОЧЕГО СТОЛА.
МОЙ БЛОГ
GRAY FUR FRAMEWORK - УДОБНАЯ И БЫСТРАЯ РАЗРАБОТКА WINAPI ПРИЛОЖЕНИЙ

Последний раз редактировалось Alex Cones; 10.11.2010 в 21:17.
Alex Cones вне форума Ответить с цитированием
Старый 10.11.2010, 21:16   #4
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

советую копатся, ибо и не такие извраты творятся
(теже потоки у VCL(да и не тока), тоже хитрость с параметром)

что такое?
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 10.11.2010, 21:21   #5
Alex Cones
Trust no one.
Старожил
 
Аватар для Alex Cones
 
Регистрация: 07.04.2009
Сообщений: 6,526
По умолчанию

А где можно найти читаемый (не MSDN) ман по созанию потоков на API?
Цитата:
что такое?
Отредактировал пост выше.
SQUARY PROJECT - НАБОР БЕСПЛАТНЫХ ПРОГРАММ ДЛЯ РАБОЧЕГО СТОЛА.
МОЙ БЛОГ
GRAY FUR FRAMEWORK - УДОБНАЯ И БЫСТРАЯ РАЗРАБОТКА WINAPI ПРИЛОЖЕНИЙ
Alex Cones вне форума Ответить с цитированием
Старый 10.11.2010, 21:25   #6
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

каждое срабатывание таймеров(обоих) должно вызывать(с разным ID, и соответственно разная процедура обработки)

насчет манов не знаю, мне msdn хватает и сорцов от Делфи
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 10.11.2010, 21:27   #7
Alex Cones
Trust no one.
Старожил
 
Аватар для Alex Cones
 
Регистрация: 07.04.2009
Сообщений: 6,526
По умолчанию

Цитата:
каждое срабатывание таймеров(обоих) должно вызывать(с разным ID, и соответственно разная процедура обработки)
Чувствуется неуверенность в голосе Каков там механизм вообще обработки таймера? Допускает ли он такое?
Если да, то на потоки можно забить.
SQUARY PROJECT - НАБОР БЕСПЛАТНЫХ ПРОГРАММ ДЛЯ РАБОЧЕГО СТОЛА.
МОЙ БЛОГ
GRAY FUR FRAMEWORK - УДОБНАЯ И БЫСТРАЯ РАЗРАБОТКА WINAPI ПРИЛОЖЕНИЙ
Alex Cones вне форума Ответить с цитированием
Старый 10.11.2010, 21:32   #8
Пепел Феникса
Старожил
 
Аватар для Пепел Феникса
 
Регистрация: 28.01.2009
Сообщений: 21,000
По умолчанию

принцип PostThreadMessage.(по сути те же сообщения)
потому и нужен цикл обработки сообщений.

а не уверен я потому что не тестировал.
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
Программа делает то что написал программист, а не то что он хотел.
Функции/утилиты ждут в параметрах то что им надо, а не то что вы хотите.
Пепел Феникса вне форума Ответить с цитированием
Старый 11.11.2010, 19:08   #9
Alex Cones
Trust no one.
Старожил
 
Аватар для Alex Cones
 
Регистрация: 07.04.2009
Сообщений: 6,526
По умолчанию

Понял, спасибо.
SQUARY PROJECT - НАБОР БЕСПЛАТНЫХ ПРОГРАММ ДЛЯ РАБОЧЕГО СТОЛА.
МОЙ БЛОГ
GRAY FUR FRAMEWORK - УДОБНАЯ И БЫСТРАЯ РАЗРАБОТКА WINAPI ПРИЛОЖЕНИЙ

Последний раз редактировалось Alex Cones; 11.11.2010 в 19:13.
Alex Cones вне форума Ответить с цитированием
Старый 11.11.2010, 19:34   #10
BOBAH13
Android Developer
Старожил Подтвердите свой е-майл
 
Аватар для BOBAH13
 
Регистрация: 19.02.2007
Сообщений: 3,708
По умолчанию

Код:
struct TIMER_STRUCT
{
  DWORD nId; // timer's id
  DWORD delay; // in ms
  DWORD ticks;
};
typedef struct TIMER_STRUCT TIMER_STRUCT;

static TIMER_STRUCT *timers;
static DWORD timerLength = 0;
static CRITICAL SECTION timerSection;
static BOOL timerActive = FALSE;

DWORD WINAPI TimerThreadProc(__in  LPVOID lpParameter)
{
  while(timerActive)
  {
    if (timerLength)
    {
       EnterCriticalSection(&timerSection);

       for (int i = 0; i < timerLength; i++)
       {
           if (GetTickCount() - timers[i].ticks >= timers[i].delay)
           {
                timers[i].ticks = GetTickCount();
                // inform user about timer's event, using timer[i] struct
           }
       }

       LeaveCriticalSection(&timerSection);
     }
     Sleep(10); // no matter make it less
   }
}

...

// initialization
InitializeCriticalSection(&timerSection);
timerActive = TRUE;
HANDLE hTimerThread = CreateThread(NULL, NULL, TimerThreadProc, NULL, NULL, NULL);

...

void CleanUp()
{
  timerActive = FALSE;
  WaitForSingleObject(hTimerThread, INFINITE);
  DeleteCriticalSection(&timerSection);
  if (timerLength)
  {
    free(timers);
    timerLength = 0;
  }
}

void AddTimer(DWORD nId, DWORD delay)
{
   EnterCriticalSection(&timerSection);
  timerLength++;
  if (timerLength == 1)
  {
    timers = (TIMER_STRUCT*)malloc(sizeof(TIMER_STRUCT) * timerLength);
  }
  else
  {
     timers = (TIMER_STRUCT*)realloc(timers, sizeof(TIMER_STRUCT) * timerLength);
  }
  timers[timerLength - 1].nId = nId;
  timers[timerLength - 1].delay = delay;
  timers[timerLength - 1].ticks = GetTickCount();
  LeaveCriticalSection(&timerSection);
}
как то так написал здесь, там уж сами разберетесь как и что для вашей системы оптимизировать. Ну удалить таймер аналогично AddTimer, зашли в секцию, сместили массив (удаляя таким образом не нужный таймер) и изменяем размер массива если --timerLength > 0, иначе free(timers);

p.s. написал на C++, на дельфи тяжело уже писать так, тут в принципе ничего тяжелого. Надеюсь это вы не примите как навязывание своего мнения насильно вам.
BOBAH13 вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Файловый менеджер akosh12345 Общие вопросы Delphi 12 11.05.2010 21:55
файловый менеджер чижик-пыжик Общие вопросы .NET 1 05.03.2010 11:51
Варианты реализации программы с использованием таймеров Casper-SC Общие вопросы Delphi 10 28.11.2009 19:18
Менеджер контента Insainer HTML и CSS 1 27.04.2008 11:06