Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Динамичесоке создание компоненты в потоке - не получается [D7, XP]


Страницы:   1 2

kay ©   (2006-04-12 12:23:00) 

Есть компонента idTcpClient, которая при отсутствии соединения вешает программу.
Решил создать тред, который содержит эту компоненту, но не знаю какого Owner'а писать при создании. Если родителя сделать основную форму, то вылетает ошибка при записи в адрес 00000000

constructor TtcpThread.Create;
begin
 inherited Create(true);
 tcpClient.Create(ovpnRestarter);
 tcpClient.OnStatus:=tcpClientStatus;
end;


заголовок

type
 TtcpThread = class(TThread)
   private
     procedure tcpClientStatus(ASender: TObject; const AStatus: TIdStatus;
       const AStatusText: String);
   protected
     procedure Execute; override;
   public
     tcpClient: TIdTCPClient;
     constructor Create;
     destructor Destroy; override;
 end;


Сергей М.   (2006-04-12 17:16:00) [1]


> как убить тред в любой момент времени, чтобы от него ничего
> не осталось?
>


Собственно тред как ОС-объект "убивается" явным или неявным вызовом TerminateThread().


sniknik   (2006-04-12 17:11:00) [2]

> как убить тред в любой момент времени, чтобы от него ничего не осталось?
в моем примере у тебя на это времени не будет... вторую кнопку нажать не успееш он уже "убьется"  и следа не останется.


sniknik   (2006-04-12 17:09:00) [3]

> я так понял при выходе их приложения вызывается метод Terminate?
нет. Terminate нужен (сдесь, в TThread)  чтобы прервать и завершить Execute (у тебя этого не используется, нормально на это проверки в цикле ставить... но у тебя и цикла нет одноразовое действие), по завершению потоку "конец"... но сам обьект потока это не освобождает, для этого надо или явно Free сделать (подождав для гарантии завершения Execute (WaitFor)), или указать освобождать автоматом (FreeOnTerminate) что у меня и сделано.

> что при выходе из приложения метод Free не понадобится?
не понадобится, оно завершится и уничтожится гораздо раньше (меньше секунды после создания и запуска... но вообще возможны варинты ;)


kay   (2006-04-12 17:04:00) [4]

как убить тред в любой момент времени, чтобы от него ничего не осталось?


kay   (2006-04-12 16:43:00) [5]


> пример вызова:
> TtcpThread.Create(false);
> и тоже все, ничего более, никаких извне вмешательств в компоненты
> потока, никаких закрытий, освождений... и т.д. это единственная
> (в этом случае) доступная тебе функция потока, его создание.
>  (повесь на кнопку start)

я так понял при выходе их приложения вызывается метод Terminate? А переменная FreeOnTerminate говорит о том, что при выходе из приложения метод Free не понадобится?


kay   (2006-04-12 16:34:00) [6]

я просто хочу сделать нормальное завершение работы программы при выполнении подключении к серверу.


Сергей М.   (2006-04-12 16:34:00) [7]


> чтобы постоянно не освобождать память


Что значит "постоянно" ? Какую память ?


> при выходе


При каком "выходе" ? Выходе откуда ?


sniknik   (2006-04-12 16:34:00) [8]

> ну извиняйте, раньше с тредами тесно не связывался.
твой пример, как он должен быть (хотя так и не понял зачем он...)

unit thread;

interface

uses Classes, SysUtils, IdTCPClient, IdComponent;

type
 TtcpThread = class(TThread)
 private
   tcpClient: TIdTCPClient;
   msg: string;
   procedure SendMessage;
   procedure tcpClientStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: String);
 protected
    procedure Execute; override;
 end;

implementation

uses main;

procedure TtcpThread.SendMessage;
begin
 ovpnRestarter.logAdd(msg);
end;

procedure TtcpThread.tcpClientStatus(ASender: TObject; const AStatus: TIdStatus; const AStatusText: String);
begin
 msg:= AStatusText;
 Synchronize(SendMessage);
end;

procedure TtcpThread.Execute;
begin
FreeOnTerminate:= true;

with TIdTCPClient.Create(nil) do
  try
    try
      OnStatus:= tcpClientStatus;
      Host:= 'www.google.com';
      Port:= 80;
      Connect();
    except
      on E: Exception do begin
        msg:= E.Message;
        Synchronize(SendMessage);
      end;
    end;
  finally
    Free;
  end;
end;

end.


и все.

пример вызова:
TtcpThread.Create(false);
и тоже все, ничего более, никаких извне вмешательств в компоненты потока, никаких закрытий, освождений... и т.д. это единственная (в этом случае) доступная тебе функция потока, его создание. (повесь на кнопку start)


kay   (2006-04-12 16:22:00) [9]

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


Сергей М.   (2006-04-12 16:19:00) [10]

В целом - бардак в логике и в выборе инструментов/алгоритмов ее реализации.


Сергей М.   (2006-04-12 16:18:00) [11]


> в execute то при этом уже нет


Зато появился Disconnect() сразу после Connect().
Ну и зачем нужна эта бестолковая логика ?


> лучше бы как у меня сделать по принципу


Про "как у тебя" (с учетом авторского вольного манипулирования возобновлением/приостановкой/уничтожением потока когда ему вздумается) я уже сказал - утечки неизбежны.


sniknik   (2006-04-12 16:15:00) [12]

> забыл, что есть 2 кнопик. start и stop

> tcp:TtcpThread;

> на запуске tcp.Resume;

> на stop:
> tcp.tcpClient.Disconnect;

а смысл? "на stop" конект уже проверится и "отвалится" (execute кончится), что ты вообще хочеш сделать?


sniknik   (2006-04-12 16:08:00) [13]

> при завершении приложения:
>  tcp.tcpClient.Disconnect;
>  tcp.Free;
тут тебе надо не tcp.tcpClient.Disconnect; делать (что неправильно, и вообще Disconnect лишний), а tcp.WaitFor; ставить.
а лучше FreeOnTerminate в создании установить в true и "забыть" о потоке сразу после создания... а то иначе смысл самого потока теряеш.

и потом убрать прямые вызовы из другого потока.
> ovpnRestarter.logAdd(AStatusText);
сделать через синхронизацию. (сообщения/критическую секцию)

> И опять вижу при этом  в [23]
но в execute то при этом уже нету ;), все нормально тут с с созданием (лучше бы как у меня сделать по принципу... но и так пойдет).


Сергей М.   (2006-04-12 16:00:00) [14]

Ну нельзя же так бессовестно врать !

Цитирую тебя :


> я его уже убрал


И опятьвижу при этом  в [23]


> constructor TtcpThread.Create;
> begin
>  inherited Create(true);
>  tcpClient := TIdTCPClient.Create(nil);
> end;


kay   (2006-04-12 15:53:00) [15]

забыл, что есть 2 кнопик. start и stop

tcp:TtcpThread;

на запуске tcp.Resume;

на stop:
tcp.tcpClient.Disconnect;


kay   (2006-04-12 15:26:00) [16]

блин. действительно не всё так гладко.

значит объясняю как всё есть. при создании формы
tcp:=TtcpThread.Create;

при завершении приложения:
 tcp.tcpClient.Disconnect;
 tcp.Free;


далее сам тред:
unit thread;

interface

uses
 Windows, SysUtils, Classes, IdTCPClient, IdComponent;

type
 TtcpThread = class(TThread)
   private
     procedure tcpClientStatus(ASender: TObject; const AStatus: TIdStatus;
       const AStatusText: String);
   protected
     procedure Execute; override;
   public
     tcpClient: TIdTCPClient;
     destructor Destroy; override;
     constructor Create;
 end;

implementation

uses main;

constructor TtcpThread.Create;
begin
 inherited Create(true);
 tcpClient := TIdTCPClient.Create(nil);
end;
//******************************************************************************
destructor TtcpThread.Destroy;
begin
 tcpClient.Free;
 inherited;
end;
//******************************************************************************
procedure TtcpThread.Execute;
begin
 try
   tcpClient.OnStatus:=tcpClientStatus;
   tcpClient.Host:='www.google.com';
   tcpClient.Port:=80;
   tcpClient.Connect();
   tcpClient.Disconnect();
 except
   on E: Exception do
     begin
       ovpnRestarter.logAdd(E.Message);
     end;
 end;
end;
//******************************************************************************
procedure TtcpThread.tcpClientStatus(ASender: TObject;
 const AStatus: TIdStatus; const AStatusText: String);
begin
 ovpnRestarter.logAdd(AStatusText);
end;
//******************************************************************************
end.


вроде всё нормально, но иногда возникает зависон все системы. проц на 100% загружен. не понимаю в чём проблема. при вызове метода tcp.tcpClient.Disconnect; в треде возникает Exception и все ошибки обрабатываются.


Сергей М.   (2006-04-12 14:33:00) [17]


> тред завершает работу - и далее всё по маслу


Далеко не "по маслу".

Вызывая в другом треде тот самый Disconnect ты провоцируешь исключительную ситуацию в треде, "висящем" на блокирующем коннекте, и никак не обрабатываешь ее при этом.


kay   (2006-04-12 14:27:00) [18]

я сначала DIsconnect делаю, тред завершает работу - и далее всё по маслу


Сергей М.   (2006-04-12 14:25:00) [19]

И тем не менее принудительное терминирование "висящего" треда (способ, выбранный тобой) - крайний вариант, которого всегда следует избегать.


kay   (2006-04-12 14:06:00) [20]

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


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо