Форум по Delphi программированию

Delphi Sources



Вернуться   Форум по Delphi программированию > Все о Delphi > Разное
Ник
Пароль
Регистрация <<         Правила форума         >> FAQ Пользователи Календарь Поиск Сообщения за сегодня Все разделы прочитаны

Ответ
 
Опции темы Поиск в этой теме Опции просмотра
  #1  
Старый 21.04.2020, 13:22
rodionov_uv rodionov_uv вне форума
Прохожий
 
Регистрация: 23.01.2017
Сообщения: 9
Версия Delphi: Delphi7
Репутация: 10
По умолчанию Зависает программа

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

Код:
procedure TMyForm.PuskButClick(Sender: TObject);
var
i, j, k: Integer;
s, str, sum, xOut, xOut1, StrAdr: String;
x: Byte;
pop: array of Byte;
WritteBuffer: array[1..19] of Byte;
ReadBuffer: array[1..21] of Byte;
BytesWritten, BytesRead: DWORD;
begin
  if PortConnect = True then
  if InitModem = True then
  begin
    for i := 1 to 4094 do
    begin
      .................................................................       
     //здесь происходит преобразование посылки в СОМ порт
      .................................................................
     
      WriteFile(Port, WritteBuffer[1], Length(WritteBuffer), BytesWritten, nil);
      ReadFile(Port, ReadBuffer, SizeOf(ReadBuffer), BytesRead, nil);

      .................................................................       
     //здесь происходит преобразование ответа из СОМ порта
      .................................................................

    end;
end;
Ответить с цитированием
  #2  
Старый 21.04.2020, 14:58
Аватар для Guaho
Guaho Guaho вне форума
Начинающий
 
Регистрация: 27.08.2017
Сообщения: 173
Версия Delphi: Delphi7
Репутация: 10
По умолчанию

Может просто по таймеру (компонент TTimer)? В свойстве Interval выставить нужный интервал (в мс) между срабатываниями таймера.
Чтоб сделать такое, нужно отказаться от конструкций "for" или "while" и прописать всё руками. Т.е. начальное состояние (i := 1) задаётся в основной программе, а инкремент переменной и опосля проверка на достижение предела, а также основные действия (преобразование посылки в СОМ порт и т.п.), прописывается в обработчике OnTimer. Таймер сразу не запускаете, сначала инициализируете переменные. Если надо - остановить таймер можно как из основной программы, так и в самом обработчике, при выполнении каких-либо условий.

Последний раз редактировалось Guaho, 21.04.2020 в 15:09.
Ответить с цитированием
  #3  
Старый 21.04.2020, 15:45
rodionov_uv rodionov_uv вне форума
Прохожий
 
Регистрация: 23.01.2017
Сообщения: 9
Версия Delphi: Delphi7
Репутация: 10
По умолчанию

А как я смогу выставить интервал, если я не знаю когда придет ответ из СОМ порта, он может придти через секунду, а может через пять.
Ответить с цитированием
  #4  
Старый 21.04.2020, 16:48
Аватар для Guaho
Guaho Guaho вне форума
Начинающий
 
Регистрация: 27.08.2017
Сообщения: 173
Версия Delphi: Delphi7
Репутация: 10
По умолчанию

Поставить малый интервал - скажем, 50 мс, тут зависит от самой задачи, насколько критичен интервал между наступлением события и началом его обработки. Ответ из порта как-то ведь проявляет себя, т.е. программно же можно определить, что он пришёл? Если да, то ставите проверку - есть ответ? Если нет, выход (т.е. "холостой ход" кода обработки приёма ответа порта).
Ответить с цитированием
  #5  
Старый 21.04.2020, 21:25
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,003
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Простой вариант: в цикл вставить вызов Application.ProcessMessages, тогда программа хоть со скрипом (в зависимости от длительности итерации цикла) будет реагировать на действия пользователя.

Сложный вариант: действительно оформить цикл как отдельный поток и сделать ассинхронный вызов, т.е. программа запускает поток, потом по таймеру проверяет, закончился ли поток. Простой вариант реализации:
Поток, в отдельном модуле:
Код:
unit WrkThread;

interface

type
  TMyThread = class(TThread)
  private
    FIsRunning : Boolean;
    FParam : String; // Какие-то данные для потока
  public
    procedure Execute; override;
    property IsRunning : Boolean read FIsRunning;
    property Param : String read FParam write FParam;
  end;

implementation

  procedure TMyThread.Execute;
  begin
    FIsRunning := True;
    Try
       For I := 1 To 4094 Do // Твой цикл
         Begin
            If Terminated Then Break; // Для того, что бы можно было прервать поток
            // Далее твой код
          End;    
    Finally
      FIsRunning := False;
    End;

end.

А теперь вызов:
Код:
type
  TForm1 = class(TForm)
  private
     T : TMyThread; // В OnCreate или в конструкторе присвоить Nil
                            // В деструкторе или в OnDestroy уничтожить если <> Nil
  end;
...
procedure TForm1.Button1Click(Sender : TObject);
begin
  If T = Nil Then T := TMyThread.Create(True);
  If T.IsRunning Then ShowMessage('Поток уже работает!')
  Else
    Begin
       T.Param := 'aaa'; // передали данные потоку
       T.Resume; // запускаем поток
       Timer1.Enabled := True; // Запускаем таймер для проверки состояния потока
    End;
end;

procedure Timer1Timer(Sender  : TObject);
begin
  If T = Nil Then Timer1.Enabled := False // Защита
  Else
    If Not T.IsRunning Then // Поток закончился
      Begin
        Timer1.Enabled := False; // выключаем таймер
        FreeAndNil(T); // Удаляем поток, что бы не болтался
        ShowMessage('Поток завершился');
      End;
end;

Это грубый пример, просто что бы показать как это все работает.
Ответить с цитированием
  #6  
Старый 21.04.2020, 22:11
rodionov_uv rodionov_uv вне форума
Прохожий
 
Регистрация: 23.01.2017
Сообщения: 9
Версия Delphi: Delphi7
Репутация: 10
По умолчанию

Сделал через таймер, вполне устраивает, даже можно остановить выполнение. Прогу пишу для себя, поэтому наверное так и оставлю, хотя понимаю что это не правильно. Просто учиться на 5ом десятке уже в лом, хоть и карантин. Спасибо огромное, что помогаете.
Ответить с цитированием
  #7  
Старый 22.04.2020, 02:24
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,003
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Таймер хорошо, если обработка укладывается в интервал срабатывания таймера. Если нет, то могут полезть глюки, которые будет тяжело ловить, бо как они будут лезть на первый взгляд в случайный момент.
Тоже самое с Application.ProcessMessages в теле цикла. Там интервал (время выполнения одной итерации цикла) определяется человеком, т.е. для человека должно казаться, что программа работает без зависаний. Это где-то 30-50 мс на выполнение одной итерации цикла.
Во всех остальных случаях - отдельный поток или процесс.
Ответить с цитированием
Этот пользователь сказал Спасибо lmikle за это полезное сообщение:
Guaho (22.04.2020)
  #8  
Старый 22.04.2020, 07:44
rodionov_uv rodionov_uv вне форума
Прохожий
 
Регистрация: 23.01.2017
Сообщения: 9
Версия Delphi: Delphi7
Репутация: 10
По умолчанию

Я просто в обработчике событий таймера сперва его отключаю, выполняю преобразования, посылаю в СОМ порт, получаю ответ, его преобразовываю и включаю обратно таймер. Приложение хоть как то реагирует. И даже можно остановить запросы.
Ответить с цитированием
Этот пользователь сказал Спасибо rodionov_uv за это полезное сообщение:
Guaho (22.04.2020)
  #9  
Старый 23.04.2020, 08:25
lmikle lmikle вне форума
Модератор
 
Регистрация: 17.04.2008
Сообщения: 8,003
Версия Delphi: 7, XE3, 10.2
Репутация: 49089
По умолчанию

Угу. Особенно надо обратить внимание на слова "хоть как то реагирует".
Опять же, если прога пишется для себя, то и так сойдет. Но если придется передавать кому-то еще, то придется менять.

ЗЫ. А вообще, лучше привыкать сразу делать правильно. Лучше набить шишек на простых примерах, а в дальнейшем уже будешь знать как делать правильно... Но это мое мнение, для себя решай сам.
Ответить с цитированием
Ответ


Delphi Sources

Опции темы Поиск в этой теме
Поиск в этой теме:

Расширенный поиск
Опции просмотра

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB-коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход


Часовой пояс GMT +3, время: 14:49.


 

Сайт

Форум

FAQ

RSS лента

Прочее

 

Copyright © Форум "Delphi Sources" by BrokenByte Software, 2004-2023

ВКонтакте   Facebook   Twitter