Форум: "Начинающим";
Текущий архив: 2006.04.30;
Скачать: [xml.tar.bz2];
ВнизДинамичесоке создание компоненты в потоке - не получается Найти похожие ветки
← →
kay © (2006-04-12 12:23) [0]Есть компонента idTcpClient, которая при отсутствии соединения вешает программу.
Решил создать тред, который содержит эту компоненту, но не знаю какого Owner"а писать при создании. Если родителя сделать основную форму, то вылетает ошибка при записи в адрес 00000000constructor 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;
← →
sniknik © (2006-04-12 12:33) [1]> но не знаю какого Owner"а писать при создании.
nil пиши, и обязательно тогда уничтожай его в деструкторе
основная форма в потоке фигурировать никак не должна
← →
kay © (2006-04-12 12:52) [2]может есть компонента уже работающая в потоке. мнепросто нужно проверять соединение с сервером. в противном случае идёт процедура работы с соединением.
← →
Сергей М. © (2006-04-12 13:11) [3]
> kay © (12.04.06 12:52) [2]
> просто нужно проверять соединение с сервером
Поток здесь вовсе не обязателен.
Подойдет любой компонент, использующий асинхронный неблокирующий режим, например, TClientSocket.
TIdTCPClient же использует синхронный блокирующий режим, но и при его использовании необязательна организация дополнительного потока - достаточно бросить на форму компонент TIdAntifreeze.
← →
kay © (2006-04-12 13:28) [4]спасибо! а то я уже реализовал тред, но есть одно НО!
после того как запустить тред (Resume), выйти из него (Suspend) и завершить приложение, то возникает ошибка записи памяти 00000000.
вот код завершения треда:if tcpClient <> nil then
tcpClient.Free;
inherited;
← →
kay © (2006-04-12 13:28) [5]спасибо! а то я уже реализовал тред, но есть одно НО!
после того как запустить тред (Resume), выйти из него (Suspend) и завершить приложение, то возникает ошибка записи памяти 00000000.
вот код завершения треда:if tcpClient <> nil then
tcpClient.Free;
inherited;
← →
Сергей М. © (2006-04-12 13:31) [6]
> вот код завершения треда:
Где этот код размещен ? В каком методе ?
← →
kay © (2006-04-12 13:33) [7]
destructor TtcpThread.Destroy;
begin
if tcpClient <> nil then
tcpClient.Free;
inherited;
end;
забыл всё скопировать...
баг возникает только если тред запустить
антифриз не подходит. он всё равно приложение вешает, по крайней мере выходить из него не хочет.
а для стандартного клиента нужно DNS lookup делать, что не хочется.
← →
kay © (2006-04-12 13:35) [8]ну и на всякий случай
procedure TtcpThread.Execute;
begin
tcpClient := TIdTCPClient.Create(nil);
tcpClient.OnStatus:=tcpClientStatus;
tcpClient.Host:="www.google.com";
tcpClient.Port:=80;
tcpClient.Connect();
end;
код запуска треда в самой программе:tcp.Resume;
код остановки треда в программе:tcp.Suspend;
после выхода из программы запускается деструктор и ошибка записи памяти 00000000
← →
kay © (2006-04-12 13:38) [9]может надо не Suspend, а Terminate?
← →
kay © (2006-04-12 13:40) [10]с Terminate такая же проблема =(
← →
Сергей М. © (2006-04-12 13:44) [11]
> для стандартного клиента нужно DNS lookup делать, что не
> хочется
В твоем случае любой компонент будет пытаться выполнять разрешение имени хоста в его IP-адрес - ты ведь указываешь хост не по адресу, а по имени ..
> баг возникает только если тред запустить
На какой конкретно строчке возникает исключение ?
← →
kay © (2006-04-12 13:51) [12]1) всё равно уж попробую тред добить. не получится - буду использовать TcpClient от борланда.
2)inherited
после нажатия F7 почемуто переходит на end метода TtcpThread.Execute;
← →
sniknik © (2006-04-12 13:53) [13]> tcpClient.OnStatus:=tcpClientStatus;
где и как описана? (проверь без нее)
потом если у тебя саздание в Execute то там и освождение делай... так примерноprocedure TtcpThread.Execute;
begin
with TIdTCPClient.Create(nil) do
try
//OnStatus:=tcpClientStatus; для теста отключить
Host:="www.google.com";
Port:=80;
Connect();
finally
Free;
end;
end;
(тогда и constructor и destructor переопределять лишнее, пойдут стандартные, писать меньше, код короче, понятнее...)
← →
kay © (2006-04-12 13:55) [14]ураЙ! получилось! вместо просто tcpClient.Free;
сделал
tcpClient.Disconnect;
tcpClient.Free;
ибо тред всё ещё работал и выполнялось убиение
← →
Сергей М. © (2006-04-12 13:56) [15]Что-то я не понял ..
Объект TIdTCPClient ты создаешь дважды - первый раз в конструкторе треда, в второй в теле Execute ...
← →
kay © (2006-04-12 13:57) [16]в конструкторе треда я его не создаю.
public
tcpClient: TIdTCPClient;
destructor Destroy; override;
← →
Сергей М. © (2006-04-12 13:59) [17]
> sniknik © (12.04.06 13:53) [13]
Так он утечку схлопочет, ибо поток может быть приостановлен при выполнении блокирующего метода Connect(), после чего объект TtcpThread уничтожен .. При этом до finally (где выполняется разрушение TIdTCPClient) дело, разумеется, не доходит
← →
Сергей М. © (2006-04-12 14:01) [18]
> в конструкторе треда я его не создаю
Цитирую самый первый твой пост :
> constructor TtcpThread.Create;
> begin
> inherited Create(true);
> tcpClient.Create(ovpnRestarter);
> tcpClient.OnStatus:=tcpClientStatus;
> end;
Выделенной жирным это что, спрашивается ?
← →
kay © (2006-04-12 14:06) [19]я его уже убрал, это первая версия была. всем спасибо. тему можно закрывать.
← →
Сергей М. © (2006-04-12 14:25) [20]И тем не менее принудительное терминирование "висящего" треда (способ, выбранный тобой) - крайний вариант, которого всегда следует избегать.
← →
kay © (2006-04-12 14:27) [21]я сначала DIsconnect делаю, тред завершает работу - и далее всё по маслу
← →
Сергей М. © (2006-04-12 14:33) [22]
> тред завершает работу - и далее всё по маслу
Далеко не "по маслу".
Вызывая в другом треде тот самый Disconnect ты провоцируешь исключительную ситуацию в треде, "висящем" на блокирующем коннекте, и никак не обрабатываешь ее при этом.
← →
kay © (2006-04-12 15:26) [23]блин. действительно не всё так гладко.
значит объясняю как всё есть. при создании формы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 и все ошибки обрабатываются.
← →
kay © (2006-04-12 15:53) [24]забыл, что есть 2 кнопик. start и stop
tcp:TtcpThread;
на запуске tcp.Resume;
на stop:
tcp.tcpClient.Disconnect;
← →
Сергей М. © (2006-04-12 16:00) [25]Ну нельзя же так бессовестно врать !
Цитирую тебя :
> я его уже убрал
И опять вижу при этом в [23]
> constructor TtcpThread.Create;
> begin
> inherited Create(true);
> tcpClient := TIdTCPClient.Create(nil);
> end;
← →
sniknik © (2006-04-12 16:08) [26]> при завершении приложения:
> tcp.tcpClient.Disconnect;
> tcp.Free;
тут тебе надо не tcp.tcpClient.Disconnect; делать (что неправильно, и вообще Disconnect лишний), а tcp.WaitFor; ставить.
а лучше FreeOnTerminate в создании установить в true и "забыть" о потоке сразу после создания... а то иначе смысл самого потока теряеш.
и потом убрать прямые вызовы из другого потока.
> ovpnRestarter.logAdd(AStatusText);
сделать через синхронизацию. (сообщения/критическую секцию)
> И опять вижу при этом в [23]
но в execute то при этом уже нету ;), все нормально тут с с созданием (лучше бы как у меня сделать по принципу... но и так пойдет).
← →
sniknik © (2006-04-12 16:15) [27]> забыл, что есть 2 кнопик. start и stop
> tcp:TtcpThread;
> на запуске tcp.Resume;
> на stop:
> tcp.tcpClient.Disconnect;
а смысл? "на stop" конект уже проверится и "отвалится" (execute кончится), что ты вообще хочеш сделать?
← →
Сергей М. © (2006-04-12 16:18) [28]
> в execute то при этом уже нет
Зато появился Disconnect() сразу после Connect().
Ну и зачем нужна эта бестолковая логика ?
> лучше бы как у меня сделать по принципу
Про "как у тебя" (с учетом авторского вольного манипулирования возобновлением/приостановкой/уничтожением потока когда ему вздумается) я уже сказал - утечки неизбежны.
← →
Сергей М. © (2006-04-12 16:19) [29]В целом - бардак в логике и в выборе инструментов/алгоритмов ее реализации.
← →
kay © (2006-04-12 16:22) [30]ну извиняйте, раньше с тредами тесно не связывался.
а криэйшн опять поставил, чтобы постоянно не освобождать память, а освобождать тоько при выходе
← →
sniknik © (2006-04-12 16:34) [31]> ну извиняйте, раньше с тредами тесно не связывался.
твой пример, как он должен быть (хотя так и не понял зачем он...)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)
← →
Сергей М. © (2006-04-12 16:34) [32]
> чтобы постоянно не освобождать память
Что значит "постоянно" ? Какую память ?
> при выходе
При каком "выходе" ? Выходе откуда ?
← →
kay © (2006-04-12 16:34) [33]я просто хочу сделать нормальное завершение работы программы при выполнении подключении к серверу.
← →
kay © (2006-04-12 16:43) [34]
> пример вызова:
> TtcpThread.Create(false);
> и тоже все, ничего более, никаких извне вмешательств в компоненты
> потока, никаких закрытий, освождений... и т.д. это единственная
> (в этом случае) доступная тебе функция потока, его создание.
> (повесь на кнопку start)
я так понял при выходе их приложения вызывается метод Terminate? А переменная FreeOnTerminate говорит о том, что при выходе из приложения метод Free не понадобится?
← →
kay © (2006-04-12 17:04) [35]как убить тред в любой момент времени, чтобы от него ничего не осталось?
← →
sniknik © (2006-04-12 17:09) [36]> я так понял при выходе их приложения вызывается метод Terminate?
нет. Terminate нужен (сдесь, в TThread) чтобы прервать и завершить Execute (у тебя этого не используется, нормально на это проверки в цикле ставить... но у тебя и цикла нет одноразовое действие), по завершению потоку "конец"... но сам обьект потока это не освобождает, для этого надо или явно Free сделать (подождав для гарантии завершения Execute (WaitFor)), или указать освобождать автоматом (FreeOnTerminate) что у меня и сделано.
> что при выходе из приложения метод Free не понадобится?
не понадобится, оно завершится и уничтожится гораздо раньше (меньше секунды после создания и запуска... но вообще возможны варинты ;)
← →
sniknik © (2006-04-12 17:11) [37]> как убить тред в любой момент времени, чтобы от него ничего не осталось?
в моем примере у тебя на это времени не будет... вторую кнопку нажать не успееш он уже "убьется" и следа не останется.
← →
Сергей М. © (2006-04-12 17:16) [38]
> как убить тред в любой момент времени, чтобы от него ничего
> не осталось?
>
Собственно тред как ОС-объект "убивается" явным или неявным вызовом TerminateThread().
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2006.04.30;
Скачать: [xml.tar.bz2];
Память: 0.56 MB
Время: 0.011 c