![]() |
|
|
|||||||
| Регистрация | << Правила форума >> | FAQ | Пользователи | Календарь | Поиск | Сообщения за сегодня | Все разделы прочитаны |
![]() |
|
|
Опции темы | Поиск в этой теме | Опции просмотра |
|
|
|
#1
|
|||
|
|||
|
Есть некий код, при выполнении которого программа зависает часа на два, пока не выполнится цикл. Знаю что можно этот цикл запихнуть в отдельный поток, а как это сделать не знаю, с потоками никогда не работал. Подскажите пожалуйста как это лучше сделать. Заранее спасибо.
Код:
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
|
||||
|
||||
|
Может просто по таймеру (компонент TTimer)? В свойстве Interval выставить нужный интервал (в мс) между срабатываниями таймера.
Чтоб сделать такое, нужно отказаться от конструкций "for" или "while" и прописать всё руками. Т.е. начальное состояние (i := 1) задаётся в основной программе, а инкремент переменной и опосля проверка на достижение предела, а также основные действия (преобразование посылки в СОМ порт и т.п.), прописывается в обработчике OnTimer. Таймер сразу не запускаете, сначала инициализируете переменные. Если надо - остановить таймер можно как из основной программы, так и в самом обработчике, при выполнении каких-либо условий. Последний раз редактировалось Guaho, 21.04.2020 в 15:09. |
|
#3
|
|||
|
|||
|
А как я смогу выставить интервал, если я не знаю когда придет ответ из СОМ порта, он может придти через секунду, а может через пять.
|
|
#4
|
||||
|
||||
|
Поставить малый интервал - скажем, 50 мс, тут зависит от самой задачи, насколько критичен интервал между наступлением события и началом его обработки. Ответ из порта как-то ведь проявляет себя, т.е. программно же можно определить, что он пришёл? Если да, то ставите проверку - есть ответ? Если нет, выход (т.е. "холостой ход" кода обработки приёма ответа порта).
|
|
#5
|
|||
|
|||
|
Простой вариант: в цикл вставить вызов 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
|
|||
|
|||
|
Сделал через таймер, вполне устраивает, даже можно остановить выполнение. Прогу пишу для себя, поэтому наверное так и оставлю, хотя понимаю что это не правильно. Просто учиться на 5ом десятке уже в лом, хоть и карантин. Спасибо огромное, что помогаете.
|
|
#7
|
|||
|
|||
|
Я просто в обработчике событий таймера сперва его отключаю, выполняю преобразования, посылаю в СОМ порт, получаю ответ, его преобразовываю и включаю обратно таймер. Приложение хоть как то реагирует. И даже можно остановить запросы.
|
| Этот пользователь сказал Спасибо rodionov_uv за это полезное сообщение: | ||
Guaho (22.04.2020)
| ||
|
#8
|
|||
|
|||
|
Угу. Особенно надо обратить внимание на слова "хоть как то реагирует".
Опять же, если прога пишется для себя, то и так сойдет. Но если придется передавать кому-то еще, то придется менять. ЗЫ. А вообще, лучше привыкать сразу делать правильно. Лучше набить шишек на простых примерах, а в дальнейшем уже будешь знать как делать правильно... Но это мое мнение, для себя решай сам. |