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

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

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

Восстановить пароль

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

Ответ
 
Опции темы Поиск в этой теме
Старый 04.09.2014, 11:40   #11
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
почитайте, что такое рекурсия. Тут есть вызов процедурой самой себя?!
Скажи и тут нет рекурсии?
Код:
procedure First;
begin
  Second;
end;
procedure Second;
begin
  Third;
end;
procedure Third;
begin
  First;
end;

First();
а в твоем примере если выставить таймер менее 10мс, через 30 сек будет EStackOverflow - обычно получаемую при глубокой рекурсии

Цитата:
Сообщение от Serge_Bliznykov Посмотреть сообщение
Это убедительно доказывает, что так, как Вы предлагаете (не использовать ProcessMessages) программировать нельзя!
И не убедительно и не доказывает, и ничего не висит
Код:
program Project1;
{$APPTYPE CONSOLE}
uses Windows;
begin
  while True do
    Sleep(10);
end.
Не стесняемся, плюсуем!

Последний раз редактировалось Slym; 04.09.2014 в 12:27.
Slym вне форума Ответить с цитированием
Старый 04.09.2014, 13:10   #12
xexxex
Пользователь
 
Регистрация: 31.07.2010
Сообщений: 52
По умолчанию

Ну, в общем, всё понятно, лучше "перебздеть, чем недобздеть" - и каждый вход в событие OnTimer либо синхронизировать внешней булевой переменной, либо в самом событии выключать\включать таймер при входе\выходе из события.
Всем спасибо!
xexxex вне форума Ответить с цитированием
Старый 04.09.2014, 14:06   #13
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

Цитата:
Скажи и тут нет рекурсии?
Вы будете удивлены, но рекурсия - она же разная бывает.
Прямой (или простой) рекурсии - тут, разумеется, нет.

цитирую с википедии:
Цитата:
В программировании рекурсия — вызов функции (процедуры) из неё же самой, непосредственно (простая рекурсия) или через другие функции (сложная или косвенная рекурсия), например, функция A вызывает функцию B, а функция B — функцию A.
соглатитесь, что если мы напишем так:
Код:
procedure Third;
begin
  // скрытый код..
end;
то уже вроде как рекурсии и нет.
поэтому, когда Вы вызываете какую-то функцию, например,
Application.Restore
Вы можете знать, есть там обработка очереди сообщений? Это рекурсивный вызов?
Это раз.

Второе. Вы меня не переубедите.
Нормальная программа должна отдавать тики операционной системе. Это и выполняется (в явную) через ProcessMessage.
При чём здесь консольное приложение
Цитата:
Код:
program Project1;
{$APPTYPE CONSOLE}
uses Windows;
begin
  while True do
    Sleep(10);
end.
я, честно говоря, не понимаю.
Вы хотите показать, что окно всё равно обрабатывается? Ну так правильно. В консоли можно же запустить программу, которая не имеет оконного обработчика и, соотвественно, не отдаёт тики системе.
А Вы написали много консольных программ, использующих TTimer?
Или это просто так пример, для поддержания разговора?
А не хотите подобный код вставить в обработчик событий формы или на таймер.
Тоже всё будет так же хорошо?


Цитата:
а в твоем примере если выставить таймер менее 10мс, через 30 сек будет EStackOverflow - обычно получаемую при глубокой рекурсии
в каком моём примере?!
В том, где я показываю, что процедуру таймера НЕЛЬЗЯ оставлять без защиты от повторного вызова и там же, где в коде написано:
Цитата:
Код:
  IntervalTimer := StrToIntDef(Edit1.Text, 0);
  if IntervalTimer < 500 then begin
     Application.MessageBox('Нельзя вводить интервал меньше 500!', 'Error', MB_OK);
     Exit
  end;
  Timer1.Interval := IntervalTimer;

Slym, скажите, а в чём Вы меня пытаетесь убедить? В том, что TTimer не нужно использовать? Или в том, что внутри TTimer нельзя писать длинные циклы? Или в том, что в длинных циклах нельзя использовать фунции, позволяющие обработать очередь оконных сообщений?



xexxex, правильно, дьявол кроется именно в деталях. Нужно смотреть конкретный код, конкретную процедуру. И, как правильно сказано в теме, не стоит вешать на таймер очень длинные процедуры, или процедуры, которые заведомо не имеют фиксированной длительности, например, ожидание ввода данных пользователем в InputBox...
Serge_Bliznykov вне форума Ответить с цитированием
Старый 04.09.2014, 14:39   #14
Slym
Участник клуба
 
Регистрация: 07.12.2011
Сообщений: 1,025
По умолчанию

в вашем примере если таймер будет выполнятся дольше, периода сработки т.е. более 1500мс (а в непредсказуемой многозадачности это влегкую): EStackOverflow - вопрос времени, и пихать такой код в таймер в приложении 24/365 я бы не стал.

А убедить пытаюсь не вас, а топикстартера, чтоб не копипастил ваши примеры
Не стесняемся, плюсуем!
Slym вне форума Ответить с цитированием
Старый 05.09.2014, 08:43   #15
Serge_Bliznykov
Старожил
 
Регистрация: 09.01.2008
Сообщений: 26,229
По умолчанию

Цитата:
EStackOverflow - вопрос времени, и пихать такой код в таймер в приложении 24/365 я бы не стал.

А убедить пытаюсь не вас, а топикстартера, чтоб не копипастил ваши примеры
Вы, наверное, не понимаете, о каких примерах идёт речь.
На мой взгляд, процедура, висящая на таймере, если есть малейшее подозрение, что время работы этой процедуры может быть БОЛЬШЕ, чем интервал таймера, может выглядеть следующим образом:

Код:
type
  TForm1 = class(TForm)
    Timer1: TTimer;
    Memo1: TMemo;
    Edit1: TEdit;
    Label1: TLabel;
    btSart: TButton;
    Label2: TLabel;
    btStop: TButton;
    procedure Timer1Timer(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btSartClick(Sender: TObject);
    procedure btStopClick(Sender: TObject);
  private
    isInTimer1 : boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.FormCreate(Sender: TObject);
begin
  Memo1.Lines.Clear;
  btStop.Enabled := false;
  isInTimer1 := false;
end;


procedure TForm1.Timer1Timer(Sender: TObject);
var i : integer;
  dt : tdatetime;
  CountTicks : DWORD;
begin

  if isInTimer1 then Exit;
  isInTimer1 := true;

  dt := now;
  Memo1.Lines.Append(' таймер сработал в '+TimeToStr(dt));

  CountTicks := GetTickCount();
  repeat
    Application.ProcessMessages();
    sleep(50);
  until GetTickCount()>= (CountTicks+5500);
  Memo1.Lines.Append(' процедура таймера, запущенная в '+TimeToStr(dt)+
                      ' завершёна в '+TimeToStr(now));
  isInTimer1 := false;
end;
вот за такой код можно не опасаться и в режиме 24/365


Хотя, конечно, на проблемы с тем, что таймер может пропускать события, это никак не влияет...

Последний раз редактировалось Serge_Bliznykov; 05.09.2014 в 08:47.
Serge_Bliznykov вне форума Ответить с цитированием
Ответ


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



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Компонент TTimer viks1 Общие вопросы Delphi 5 14.05.2012 19:56
TTimer Китос Общие вопросы Delphi 5 24.09.2011 19:03
TTimer ak3000 Компоненты Delphi 9 14.11.2008 18:18
TTimer в Delphi AlexandrSid Общие вопросы Delphi 7 23.05.2008 14:10
TTimer amandra Компоненты Delphi 3 19.11.2007 13:54