Thread прервать по TimeOut
Модераторы: Duncon, Naeel Maqsudov, Игорь Акопян, Хыиуду
Что-то никак не найду нужную ссылочку.
Задача решена - обращение к веб-ресурсам. Это в нитях все работает.
Но столкнулся с проблемкой. Как-то завис процесс и все.
При чем он мог завсинуть и при запросе (там таймаут есть), так и при обработке, т.е. в Thread
Поэтому возника такой вопрос: как задать время выполнения Thread
MyTHread:=TMyThread.Create(true);
MyTHread.FreeOnTerminate:=True;
MyTHread.Resume.
Вот как задать TaimOut, чтобы, скажем через 100 секунд процесс принудительно Execute ?
Задача решена - обращение к веб-ресурсам. Это в нитях все работает.
Но столкнулся с проблемкой. Как-то завис процесс и все.
При чем он мог завсинуть и при запросе (там таймаут есть), так и при обработке, т.е. в Thread
Поэтому возника такой вопрос: как задать время выполнения Thread
MyTHread:=TMyThread.Create(true);
MyTHread.FreeOnTerminate:=True;
MyTHread.Resume.
Вот как задать TaimOut, чтобы, скажем через 100 секунд процесс принудительно Execute ?
К сожалению, класс TThread не предусматривает возможности задать интервал ожидания.
Проще всего это сделать так: создать таймер с нужным интервалом и в обработчике OnTimer()
- либо 1) вызывать MyTHread.Terminate() - это в случае, если потоковая функция представляет собой цикл - тогда следить за состоянием св-ва Terminated и завершать ее при Terminated = True;
- либо 2) просто убивать поток с помощью TerminateThread(MyTHread.Handle) - но при этом останутся неосвобожденные ресурсы.
Проще всего это сделать так: создать таймер с нужным интервалом и в обработчике OnTimer()
- либо 1) вызывать MyTHread.Terminate() - это в случае, если потоковая функция представляет собой цикл - тогда следить за состоянием св-ва Terminated и завершать ее при Terminated = True;
- либо 2) просто убивать поток с помощью TerminateThread(MyTHread.Handle) - но при этом останутся неосвобожденные ресурсы.
Попробовал создать Timer прямо в потоке. Не срабатывает OnTime.
Не могли бы вы привести пример или ссылку на данный пример.
Не могли бы вы привести пример или ссылку на данный пример.
Насчет таймеров посмотрите пока это forum/viewtopic.php?t=247
Использование waitable timer (пример из MSDN):
Использование waitable timer (пример из MSDN):
Код: Выделить всё
#include <windows.h>
#include <stdio.h>
int main()
{
HANDLE hTimer = NULL;
LARGE_INTEGER liDueTime;
liDueTime.QuadPart=-100000000;
// Create a waitable timer.
hTimer = CreateWaitableTimer(NULL, TRUE, "WaitableTimer");
if (!hTimer)
{
printf("CreateWaitableTimer failed (%d)\n", GetLastError());
return 1;
}
printf("Waiting for 10 seconds...\n");
// Set a timer to wait for 10 seconds.
if (!SetWaitableTimer(
hTimer, &liDueTime, 0, NULL, NULL, 0))
{
printf("SetWaitableTimer failed (%d)\n", GetLastError());
return 2;
}
// Wait for the timer.
if (WaitForSingleObject(hTimer, INFINITE) != WAIT_OBJECT_0)
printf("WaitForSingleObject failed (%d)\n", GetLastError());
else printf("Timer was signaled.\n");
return 0;
}
Прошу прощения за телеграфный стиль предыдущего сообщения
- не было времени вступать в диалог.
Заранее скажу, что TTimer не может использоваться в консольном приложении; пример с waitable timer как раз для этой ситуации. У Вас, скорее всего, главный поток приложения GUI-ный, т.е. поддерживает окооный интерфейс и очередь сообщений. Если так, то нужно просто при запуске очередного потока (thread) создавать новый объект типа TTimer, настраивать реакцию на событие OnTimer (при этом процедура для всех таймеров может быть одна - различать, от кого пришло сообщение можно по Sender) и запускать таймер.
Вот как это можно сделать (в примере на OnTimer повешен вывод из текущего потока на главную форму):

Опишите подробнее, как создаете таймер, как настраиваете OnTime.Попробовал создать Timer прямо в потоке. Не срабатывает OnTime.
Заранее скажу, что TTimer не может использоваться в консольном приложении; пример с waitable timer как раз для этой ситуации. У Вас, скорее всего, главный поток приложения GUI-ный, т.е. поддерживает окооный интерфейс и очередь сообщений. Если так, то нужно просто при запуске очередного потока (thread) создавать новый объект типа TTimer, настраивать реакцию на событие OnTimer (при этом процедура для всех таймеров может быть одна - различать, от кого пришло сообщение можно по Sender) и запускать таймер.
Вот как это можно сделать (в примере на OnTimer повешен вывод из текущего потока на главную форму):
Код: Выделить всё
unit MyThread;
interface
uses
SysUtils, Classes, Dialogs, Graphics, Windows, ExtCtrls, StdCtrls;
type
TMyThread = class(TThread)
private
{ Private declarations }
fInfo: TLabel;
fTimer: TTimer;
procedure DoOnTimer(pSender: TObject);
procedure OutputOnTimer;
procedure ExecProc;
protected
procedure Execute; override;
public
constructor Create(pSuspended: Boolean);
destructor Destroy; override;
end;
implementation
uses Main, Math;
{ Important: Methods and properties of objects in visual components can only be
used in a method called using Synchronize, for example,
Synchronize(UpdateCaption);
and UpdateCaption could look like,
procedure TMyThread.UpdateCaption;
begin
Form1.Caption := 'Updated in a thread';
end; }
{ TMyThread }
constructor TMyThread.Create(pSuspended: Boolean);
begin
inherited Create(pSuspended);
Priority := tpNormal;
FreeOnTerminate := True;
fTimer := TTimer.Create(nil);
fTimer.Interval := 1000;
fTimer.OnTimer := DoOnTimer;
fInfo := TLabel.Create(Form1);
fInfo.Parent := Form1;
fInfo.Left := 40;
fInfo.Top := Form1.btnStop.Top+30+20*Form1.ThdCount;
end;
destructor TMyThread.Destroy;
begin
Synchronize(fTimer.Free);
Synchronize(fInfo.Free);
inherited;
end;
procedure TMyThread.DoOnTimer(pSender: TObject);
begin
if not Suspended then begin
Synchronize(OutputOnTimer);
end;
end;
procedure TMyThread.Execute;
begin
{ Place thread code here }
repeat
Synchronize(ExecProc);
until Terminated;
end;
procedure TMyThread.ExecProc;
var v: Extended;
begin
v := NAN;
try
v := Cos(Random*Pi);
except
on E: Exception do MessageDlg(E.Message, mtError, [mbOk], E.HelpContext);
end;
fInfo.Caption := Format('Current value = %g', [v]);
end;
procedure TMyThread.OutputOnTimer;
begin
with Form1.sbThreadStatus do begin
Panels[0].Text := Format('ThreadID: %d OnTimer', [ThreadID]);
Panels[1].Text := Format('Threads running: %d', [Form1.ThdCount]);
end;
end;
end.
Спасибо. Я создавал таймер не в методе Create, а в Execute.
Правильно ли я понял, что для прерывания можно прописать:
procedure TMyThread.OutputOnTimer;
begin
Terminate();
end;
И все правильно завершится ?
Правильно ли я понял, что для прерывания можно прописать:
procedure TMyThread.OutputOnTimer;
begin
Terminate();
end;
И все правильно завершится ?
да, именно так
Еще раз огромное спасибо.
В этом случае по памяти все нормально будет? все освободится? Даже если в Execute создавались другие компоненты?
(если для ответа надо пробовать - то ладно, попозже сам эксперименты поставлю) :-)
В этом случае по памяти все нормально будет? все освободится? Даже если в Execute создавались другие компоненты?
(если для ответа надо пробовать - то ладно, попозже сам эксперименты поставлю) :-)
По-хорошему, все выделенные ресурсы (компоненты и пр.) нужно освобождать в обработчике события OnTerminate. Полезно еще установить св-во FreeOnTerminate = True, тогда сам thread-объект будет автоматически освобожден по завершении.
Ок, переписвываем:
procedure TMyThread.OutputOnTimer;
begin
FreeOnTerminate:= True
end;
procedure TMyThread.OutputOnTimer;
begin
FreeOnTerminate:= True
end;