Thread прервать по TimeOut

Модераторы: Duncon, Naeel Maqsudov, Игорь Акопян, Хыиуду

UUU
Сообщения: 309
Зарегистрирован: 17 фев 2004, 09:27
Откуда: Иваново
Контактная информация:

26 окт 2004, 23:00

Что-то никак не найду нужную ссылочку.
Задача решена - обращение к веб-ресурсам. Это в нитях все работает.
Но столкнулся с проблемкой. Как-то завис процесс и все.
При чем он мог завсинуть и при запросе (там таймаут есть), так и при обработке, т.е. в Thread

Поэтому возника такой вопрос: как задать время выполнения Thread

MyTHread:=TMyThread.Create(true);
MyTHread.FreeOnTerminate:=True;
MyTHread.Resume.

Вот как задать TaimOut, чтобы, скажем через 100 секунд процесс принудительно Execute ?
Eugie
Сообщения: 707
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

27 окт 2004, 17:46

К сожалению, класс TThread не предусматривает возможности задать интервал ожидания.

Проще всего это сделать так: создать таймер с нужным интервалом и в обработчике OnTimer()

- либо 1) вызывать MyTHread.Terminate() - это в случае, если потоковая функция представляет собой цикл - тогда следить за состоянием св-ва Terminated и завершать ее при Terminated = True;

- либо 2) просто убивать поток с помощью TerminateThread(MyTHread.Handle) - но при этом останутся неосвобожденные ресурсы.
UUU
Сообщения: 309
Зарегистрирован: 17 фев 2004, 09:27
Откуда: Иваново
Контактная информация:

27 окт 2004, 23:01

Попробовал создать Timer прямо в потоке. Не срабатывает OnTime.
Не могли бы вы привести пример или ссылку на данный пример.
Eugie
Сообщения: 707
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

28 окт 2004, 16:38

Насчет таймеров посмотрите пока это forum/viewtopic.php?t=247

Использование 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;
}
Eugie
Сообщения: 707
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

29 окт 2004, 10:07

Прошу прощения за телеграфный стиль предыдущего сообщения :) - не было времени вступать в диалог.
Попробовал создать Timer прямо в потоке. Не срабатывает OnTime.
Опишите подробнее, как создаете таймер, как настраиваете 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.
UUU
Сообщения: 309
Зарегистрирован: 17 фев 2004, 09:27
Откуда: Иваново
Контактная информация:

29 окт 2004, 10:19

Спасибо. Я создавал таймер не в методе Create, а в Execute.
Правильно ли я понял, что для прерывания можно прописать:

procedure TMyThread.OutputOnTimer;
begin
Terminate();
end;


И все правильно завершится ?
Eugie
Сообщения: 707
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

29 окт 2004, 10:24

да, именно так
UUU
Сообщения: 309
Зарегистрирован: 17 фев 2004, 09:27
Откуда: Иваново
Контактная информация:

29 окт 2004, 10:58

Еще раз огромное спасибо.
В этом случае по памяти все нормально будет? все освободится? Даже если в Execute создавались другие компоненты?
(если для ответа надо пробовать - то ладно, попозже сам эксперименты поставлю) :-)
Eugie
Сообщения: 707
Зарегистрирован: 17 фев 2004, 23:59
Откуда: SPb

29 окт 2004, 16:50

По-хорошему, все выделенные ресурсы (компоненты и пр.) нужно освобождать в обработчике события OnTerminate. Полезно еще установить св-во FreeOnTerminate = True, тогда сам thread-объект будет автоматически освобожден по завершении.
UUU
Сообщения: 309
Зарегистрирован: 17 фев 2004, 09:27
Откуда: Иваново
Контактная информация:

29 окт 2004, 17:15

Ок, переписвываем:
procedure TMyThread.OutputOnTimer;
begin
FreeOnTerminate:= True
end;
Ответить