Форум: "Начинающим";
Текущий архив: 2006.12.17;
Скачать: [xml.tar.bz2];
ВнизПодскажите почему я не могу освободить поток Найти похожие ветки
← →
KyRo (2006-12-01 11:30) [0]Я создаю поток
StatusATMT:=TStatusATMThread.Create(False);
constructor TStatusATMThread.Create(CreateSuspennded: Boolean);
begin
inherited Create(CreateSuspennded) ;
// Создаем сервер
ServerS:=TServerSocket.Create(nil);
ServerS.OnClientError:=ServerClientError;
ServerS.OnClientRead:=ServerClientRead;
ClientS:=TClientSocket.Create(nil);
ClientS.OnError:=ClientError;
ClientS.OnConnect:=ClientConnect;
ClientS.ClientType:=ctNonBlocking;
//priority:=tpLowest;
Resume;
end;
В EXECUTE есть соответственно цикл который запускает сокет сервер и клиент и начинает работать по сети с клиентамиWhile not Terminated do
begin
ATML:=TStringList.Create;
{Запрашиваем список ай пи адресов клиентов которых надо опросить}
if LoadATMList(ATML) =False
then
begin
ATML.Free;
Terminate;
end;
{Запускаем опрос}
For i := 0 to ATML.Count -1 do
begin
{Запускаем сервер}
ServerS.ServerType:=stNonBlocking;
ServerS.Port:=50018;
ServerS.Active:=True;
и.т.д
При выходе из этого цикла (то есть в конце экзекют) я освобождаю сервер и клиент
ServerS.Free;
ClientS.Free;
ATML.Free;
И вот из основной программы я пытаюсь его освободить и на этом программа залипает !!!
StatusATMT.Terminate;
StatusATMT.Free;
StatusATMT -это глобальная переменная С типом TStatusATMThread
Подскажите из за чего это может происходить ?
← →
clickmaker © (2006-12-01 11:34) [1]
> if LoadATMList(ATML) =False
> then
> begin
> ATML.Free;
> Terminate;
> end;
а почему не просто Break? И зачем свойства в цикле каждый раз по новой назначать?
← →
С (2006-12-01 11:39) [2]Причина в "и. т. д."
← →
KyRo (2006-12-01 11:40) [3]
> а почему не просто Break?
Можно и Break? не спорю но тогда надо освободить сервер и клиент или они вместе с потоком освободятся автоматом когда я его уничтожу?
> И зачем свойства в цикле каждый раз по новой назначать?
Свойства чего сервера ? Если да то для разных клиентов разные параметры.
← →
KyRo (2006-12-01 11:42) [4]
> Причина в "и. т. д."
:)
Держите расшифровку (весь execute)
var
ATML:TStringList;
i:Integer;
ipclientIMG:String;
//**************************************************
{Функция определяет количество банкоматов с прописаным ай пи адресом}
Function LoadATMList(var ATML:TStringList):Boolean;
var
DBCONNECT:TADOConnection;
ADOQUERY:TADOQuery;
ConnectionReg:Tregistry;
ConString:String;
i:Integer;
begin
// Создаем компонент соединения с бд
DBCONNECT:=TADOConnection.Create(nil);
With DBCONNECT do
begin
ConnectionReg:=TRegistry.Create;
ConnectionReg.RootKey:=HKEY_CURRENT_USER;
ConnectionReg.OpenKey("\SOFTWARE\LogBn\Settings\", false);
ConnectionString:=ConnectionReg.ReadString("ConnectionString");
DBCONNECT.LoginPrompt:=False;
Connected := True;
end;
ConnectionReg.Free;
//Создаем кмпонент АДО ТЕЙБЛ
ADOQUERY:=TADOQuery.Create(nil);
// Задаем параметры соединения
With ADOQUERY do
begin
Connection:= DBCONNECT;
ADOQUERY.SQL.Add("Select * from ATM_NAME where IP_CLIENT IS NOT NULL order by NAME");
Active:=True;
end;
if ADOQUERY.RecordCount = 0
then
begin
ADOQUERY.Free;
DBCONNECT.Connected:=False;
DBCONNECT.Free;
Result:=False;
Exit;
end;
ADOQUERY.First;
For i:= 1 to ADOQUERY.RecordCount do
begin
ATML.Add(ADOQUERY.FieldValues["IP_CLIENT"]);
ADOQUERY.Next;
end;
if ATML.Count > 0
then
begin
Result:=True;
ADOQUERY.Free;
DBCONNECT.Connected:=False;
DBCONNECT.Free;
end
else
begin
ADOQUERY.Free;
DBCONNECT.Connected:=False;
DBCONNECT.Free;
Result:=False;
end;
end;
//**************************************************
{Функция модификации записи статуса клиента в базе данных}
Procedure ModifyBD(IPADDR:String);
var
DBCONNECT:TADOConnection;
ADOQUERY:TADOQuery;
ConnectionReg:Tregistry;
ConString:String;
begin
// Создаем компонент соединения с бд
DBCONNECT:=TADOConnection.Create(nil);
With DBCONNECT do
begin
ConnectionReg:=TRegistry.Create;
ConnectionReg.RootKey:=HKEY_CURRENT_USER;
ConnectionReg.OpenKey("\SOFTWARE\LogBn\Settings\", false);
ConnectionString:=ConnectionReg.ReadString("ConnectionString");
DBCONNECT.LoginPrompt:=False;
Connected := True;
end;
ConnectionReg.Free;
//Создаем кмпонент АДО ТЕЙБЛ
ADOQUERY:=TADOQuery.Create(nil);
// Задаем параметры соединения
With ADOQUERY do
begin
Connection:= DBCONNECT;
ADOQUERY.SQL.Add("Select * from ATM_NAME where IP_CLIENT="+#39+IPADDR+#39);
Active:=True;
end;
if ADOQUERY.RecordCount = 0
then
begin
ADOQUERY.Free;
DBCONNECT.Free;
Exit;
end;
If ResMassag<>""
then
begin
ADOQUERY.Edit;
ADOQUERY.FieldByName("STATUS_CLIENT").Value:="Работает";
ADOQUERY.Post;
end
else
begin
ADOQUERY.Edit;
ADOQUERY.FieldByName("STATUS_CLIENT").Value:="Не доступен";
ADOQUERY.Post;
end;
ADOQUERY.Active:=False;
DBCONNECT.Connected:=False;
ADOQUERY.Free;
DBCONNECT.Free;
end;
//**************************************************
begin
While not Terminated do
begin
ATML:=TStringList.Create;
{Запрашиваем список ай пи адресов клиентов которых надо опросить}
if LoadATMList(ATML) =False
then
begin
ATML.Free;
Terminate;
end;
{Запускаем опрос}
For i := 0 to ATML.Count -1 do
begin
{Запускаем сервер}
ServerS.ServerType:=stNonBlocking;
ServerS.Port:=50018;
ServerS.Active:=True;
// Cоздаем клиент
ClientS.Active:=False;
ipclientIMG:=ATML.Strings[i];
DelSpacesUn(ipclientIMG);
Messag:=ipclientIMG;
ClientS.Address:=ipclientIMG;
ClientS.Port:=50017;
ClientS.Tag:=0;
ResMassag:="";
StatusWake:=0;
Application.ProcessMessages ;
try
ClientS.Active:=True;
Application.ProcessMessages ;
Except
Continue;
end;
{---! Запускаем таймер который будет следить за работай сервера }
TimerServerWork:=TTimer.Create(nil);
TimerServerWork.OnTimer:=TimerServerWorkOnTimer;
TimerServerWork.Interval:=10000;
TimerServerWork.Enabled:=True;
//Ожидаем ответа или выхода таймаута
While (StatusWake = 0)and(not Terminated) do Application.ProcessMessages ;
//Тушим сервер и таймер
TimerServerWork.Enabled:=False;
TimerServerWork.Free;
ServerS.Active:=False;
//Модифицируем базу данных
ModifyBD(Messag);
end;
ATML.Free;
end;
ServerS.Active:=False;
ClientS.Active:=False;
try
ServerS.Free;
ClientS.Free;
ATML.Free;
except
Break;
end;
← →
clickmaker © (2006-12-01 11:45) [5]ну как вариант, можно в отладчике прогнать. Посмотреть, на какой строке залипает
← →
sniknik © (2006-12-01 11:46) [6][1] +
> из за чего это может происходить ?
в цикле, который выполняется долго, нет проверки на Terminated и выхода если установлен, вот он его до конца и прокручивает.
++
ATML:=TStringList.Create;
try
//все остальное сдесь
//например
if LoadATMList(ATML) = False then Break; //или Exit если вдруг вложенных циклов станет больше одного, и нужно выйти а Break этого уже позволит.
....
finally
ATML.Free;
end;
← →
Сергей М. © (2006-12-01 11:48) [7]
> KyRo
В коде куча грубых ошибок.
Проще все переписать с нуля, чем их исправлять.
p.s.
Насколько мне помнится, ты уже получал граблями за обращение к VCL-компонентам в доп.потоке, и теперь вновь на них наступаешь.
← →
sniknik © (2006-12-01 11:48) [8]> Application.ProcessMessages ;
в потоке ????? убери пока больше никто не видел...
← →
KyRo (2006-12-01 11:52) [9]
> try
> //все остальное сдесь
> //например
> if LoadATMList(ATML) = False then Break; //или Exit если
> вдруг вложенных циклов станет больше одного, и нужно выйти
> а Break этого уже позволит.
>
> ....
>
> finally
> ATML.Free;
> end;
Так да можно сделать.
> [1] +
> > из за чего это может происходить ?
> в цикле, который выполняется долго, нет проверки на Terminated
> и выхода если установлен, вот он его до конца и прокручивает.
>
> //Ожидаем ответа или выхода таймаута
> While (StatusWake = 0)and(not Terminated) do Application.
> ProcessMessages ;
Имеете ввиду вот этот цикл ? Поставить после него проверку на Terminated
и если есть то Exit ? Я правильно понял ?
> ну как вариант, можно в отладчике прогнать. Посмотреть,
> на какой строке залипает
Залипает на строке которй я его пытаюсь освободить
← →
KyRo (2006-12-01 11:54) [10]
> В коде куча грубых ошибок.
> Проще все переписать с нуля, чем их исправлять.
Это легче всего сказать !!
> Насколько мне помнится, ты уже получал граблями за обращение
> к VCL-компонентам в доп.потоке, и теперь вновь на них наступаешь.
>
> > Application.ProcessMessages ;
> в потоке ????? убери пока больше никто не видел...
Я не обращаюсь в всл Application.ProcessMessages ; для того что бы работали события таймера ,клиента и сервера которые функционируют в этом потоке
← →
clickmaker © (2006-12-01 11:58) [11]
> Залипает на строке которй я его пытаюсь освободить
procedure TThread.Terminate;
begin
FTerminated := True;
end;
здесь залипать нечему, как видишь
destructor TThread.Destroy;
begin
if (FThreadID <> 0) and not FFinished then
begin
Terminate;
if FCreateSuspended then
Resume;
WaitFor;
end;
а вот здесь может залипнуть на WaitFor. Значит, где-то внутри Execute
← →
Сергей М. © (2006-12-01 12:07) [12]
> Я не обращаюсь в всл Application.ProcessMessages
Здрасть-приехали !
Application - это что по-твоему ? Не VCL-объект, надо понимать ?
> для того что бы работали события таймера ,клиента и сервера
> которые функционируют в этом потоке
Насчет таймера в код не вникал, но более чем уверен - он там нафиг не нужен.
По поводу же клиента и сервера тебе, как помнится, уже приводили код:
while not Terminated and GetMessage(Msg, 0, 0, 0) do
DispatchMessage(Msg);
И все ! И никаких Application.ProcessMessages тут не нужно ! Все при этом расчудесно работает)
← →
sniknik © (2006-12-01 12:09) [13]> Я не обращаюсь в всл Application.ProcessMessages ; для того что бы работали события таймера ,клиента и сервера которые
> функционируют в этом потоке
да? покажи выборку сообщений своего потока, и зачем одноименно назвал (Application) обрабатывающий поток с основным?...
сдается мне мил человек, что ты ... эта, в кучу все смешал, и пользуешься без разбора в потоке глобальными таймерами/переменными, из потока их только стартуешь.
← →
Сергей М. © (2006-12-01 12:11) [14]Ну и еще один крайне важный момент:
CoInitialize(nil);
try
.. работа с АДО, от начала и до конца ...
finally
CoUninitialize;
end;
Выделенное жирным обязательно для исполнения в каждом доп.потоке, в котором осуществляется работа с АДО (и не только с ним)
В противном случае будет возбуждено исключение и твой поток "залипнет", поскольку в нем нет общей обработки исключений.
← →
sniknik © (2006-12-01 12:13) [15]Сергей М. © (01.12.06 12:07) [12]
> while not Terminated and GetMessage(Msg, 0, 0, 0) do
> DispatchMessage(Msg);
это у него не сработает, т.к. до этого просто не дойдет, до него куча кода который уже "залипает", тут для этого при такой структуре нужен отдельный поток обрабатывающий рабочий, и вот в нем уже можно делать так. (но лучше конечно делать правильно ;)
← →
Сергей М. © (2006-12-01 12:16) [16]
> sniknik © (01.12.06 12:13) [15]
> это у него не сработает, т.к. до этого просто не дойдет,
> до него куча кода который уже "залипает"
Это понятно.
Но, согласись, грамотная организация такого цикла (если он необходим, а он при данной логике действительно необходим) - один из ключевых моментов в сквозной логике.
← →
sniknik © (2006-12-01 12:16) [17]> Имеете ввиду вот этот цикл ? Поставить после него проверку на Terminated
> и если есть то Exit ? Я правильно понял ?
нет. я имел ввиду первый показанный цикл, и не после него а в нем. разница однако!
> {Запускаем опрос}
> For i := 0 to ATML.Count -1 do
> begin
> {Запускаем сервер}
> ServerS.ServerType:=stNonBlocking;
> ServerS.Port:=50018;
> ServerS.Active:=True;
> и.т.д
но после показан код который разбирать совсем не хочется, его проще переделать.
← →
KyRo (2006-12-01 12:22) [18]
> CoInitialize(nil);
> try
> .. работа с АДО, от начала и до конца ...
> finally
> CoUninitialize;
> end;
Что это такое можно по подробнее ?
> это у него не сработает, т.к. до этого просто не дойдет,
> до него куча кода который уже "залипает", тут для этого
> при такой структуре нужен отдельный поток обрабатывающий
> рабочий, и вот в нем уже можно делать так. (но лучше конечно
> делать правильно ;)
тут вы не правы все отлично работает . Не могу только завершить поток.
А таймер мне нужен что бы сделать тайм аут на то сколько сервер будет ожидать ответа от клиента. И когда переходить на обработку следующего
← →
Сергей М. © (2006-12-01 12:27) [19]
> Что это такое можно по подробнее ?
>
Подробности - в справке и msdn.
А вкратце - эти ф-ции инициализируют/деинициализируют COM-подсистему для работы в текущем код.потоке. АДО как раз и базируется на OLE/COM.
← →
clickmaker © (2006-12-01 12:27) [20]
> А таймер мне нужен что бы сделать тайм аут на то сколько
> сервер будет ожидать ответа от клиента
а почему бы Sleep не сделать? или через события? TEvent, WaitFor
← →
sniknik © (2006-12-01 12:38) [21]> тут вы не правы все отлично работает . Не могу только завершить поток.
именно про это и сказано, пока работает один код до другого не дойдет, т.е. то что ты не можеш завершить поток это и является "нерабочестью" про которую и сказано. и причины объяснены, не будеш ничего менять так и останется.
про CoInitialize(nil); все правда, не веришь твое дело.
clickmaker © (01.12.06 12:27) [20]
> а почему бы Sleep не сделать? или через события? TEvent, WaitFor
;о)) опять же, а как оно будет работать если уже чтото выполняется и до Sleep или ожидания событий попросту не доходит дело?
тут парой изменений не обойдешься, нужно в корне чтото менять.
← →
Сергей М. © (2006-12-01 12:42) [22]
> KyRo
Я таки не понимаю, почему ты не пользуешься встроенным отладчиком для поиска ошибок в своем алгоритме.
Но даже если на это есть серьезные причины (в чем сомневаюсь) возьми себе за правило при разработке не самой тривиальной поточной логики заключать тело метода Execute в try..except, чтобы можно было протоколировать неожиданные исключения, о которых ты изначально не подозреваешь.
Вот так:
procedure TMyThread.Execute;
begin
try
.. все что угодно ...
except
on e:exception do
WriteToLog("ThreadId=" + IntToStr(ThreadId) + " " + e.Classname + " " + e.Message);
end;
end;
← →
KyRo (2006-12-01 12:53) [23]
> а почему бы Sleep не сделать?
Не подходит потому что тайм аут у меня 2 -е минуты а сообщение от клиента может прийти через 3 сек в зависимости от работы канала
> про CoInitialize(nil); все правда, не веришь твое дело.
Про CoInitialize(nil); не чего плохого не говорил !! Просто не знал про это , щас буду делать! Вот только вопрос чего тогда у меня ADO работает в потоке без инициализации ?
> именно про это и сказано, пока работает один код до другого
> не дойдет, т.е. то что ты не можеш завершить поток это и
> является "нерабочестью" про которую и сказано. и причины
> объяснены, не будеш ничего менять так и останется.
Весь код в потоке работает цикл повторяется и едет по кругу. Все статусы клиентов обновляются вот только его можно запустить а выключить не могу.
← →
KyRo (2006-12-01 13:02) [24]
> Вот так:
>
> procedure TMyThread.Execute;
> begin
> try
> .. все что угодно ...
> except
> on e:exception do
> WriteToLog("ThreadId=" + IntToStr(ThreadId) + " " +
> e.Classname + " " + e.Message);
> end;
> end;
> <Цитата>
Щас так и сделаю
> Я таки не понимаю, почему ты не пользуешься встроенным отладчиком
> для поиска ошибок в своем алгоритме.
Имееш в виду брек поинты ? Ими пользуюсь
← →
Leonid Troyanovsky © (2006-12-01 13:12) [25]
> Сергей М. © (01.12.06 12:42) [22]
> WriteToLog("ThreadId=" + IntToStr(ThreadId) + " " +
> e.Classname + " " + e.Message);
Лучше, IMHO, OutputDebugString, чтобы приучаться к
отладочным средствам, таким как, например, EventLog.
--
Regards, LVT.
← →
sniknik © (2006-12-01 13:17) [26]> Вот только вопрос чего тогда у меня ADO работает в потоке без инициализации?
используется инициализация из основного потока в котором она делается при подключении какогото модуля (не помню какого).
← →
Сергей М. © (2006-12-01 13:52) [27]
> sniknik © (01.12.06 13:17) [26]
> не помню какого
ComObj
Скорей всего у автора этот юнит задействован, раз он миновал засаду с исключением по этому поводу.
> KyRo (01.12.06 13:02) [24]
> Имееш в виду брек поинты ? Ими пользуюсь
Не заметно.
← →
icWasya © (2006-12-01 13:59) [28]а как вот после вот этого
if LoadATMList(ATML) =False
then
begin
ATML.Free; // <<==-- вот это
Terminate;
end;
выполняется вот это
{Запускаем опрос}
For i := 0 to ATML.Count -1 do
← →
KyRo (2006-12-01 14:01) [29]
> > KyRo (01.12.06 13:02) [24]
>
>
> > Имееш в виду брек поинты ? Ими пользуюсь
>
>
> Не заметно.
Я ж говорю что весь код внутри у меня работает . То есть сам алгоритм опроса клиентов полностью функционирует и цикл проходит по всей выборке из базы и потом начинает все с начала ! А вот прервать из основного потока(А точнее не прервать потому что Тerminate выполняется ) А вызвать Thread.Free что бы освободить память не получается программа на этом зависает. При этом брикпоинты не чего не показывают
← →
Сергей М. © (2006-12-01 14:04) [30]
> внутри у меня
Я даже боюсь предположить, где в тебе находится это самое "внутри")
> брикпоинты не чего не показывают
>
Значит не там их расставляешь.
← →
KyRo (2006-12-01 14:05) [31]
> ComObj
>
> Скорей всего у автора этот юнит задействован, раз он миновал
> засаду с исключением по этому поводу.
Нету его вот все модулиWindows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, DBCtrls, fDBCtrls, Grids, ValEdit, ExtCtrls, ComCtrls,
Buttons, CheckLst, fCtrls, ImgList, ParsM, IniFiles, Registry, Menus,
DBGrids, Tray ,ADOConEd ,ADODB ,ClipBrd, AppEvnts ,CopyFile, ScktComp,
Gauges, Winsock, TrayIconU ,ShellApi,StatusATMThread,db;
> icWasya © (01.12.06 13:59) [28]
> а как вот после вот этого
> if LoadATMList(ATML) =False
> then
> begin
> ATML.Free; // <<==-- вот это
> Terminate;
> end;
> выполняется вот это
> {Запускаем опрос}
> For i := 0 to ATML.Count -1 do
Вот это происходит только тогда когда функция вернула пустой список и Фалсе после этого фор выполнять нет смысла
← →
Сергей М. © (2006-12-01 14:18) [32]
> KyRo (01.12.06 14:05) [31]
> Нету его вот все модули
Это не модули, а юниты.
Значит один из этих юнитов использует ComObj в uses.
Либо где-то среди них явно вызывается сабж.
Только так, третьего не дано.
← →
KyRo (2006-12-01 15:07) [33]
> Это не модули, а юниты.
>
> Значит один из этих юнитов использует ComObj в uses.
> Либо где-то среди них явно вызывается сабж.
> Только так, третьего не дано.
Ну в любом случае если вы говорите что так будет правильно, сделаю так.
← →
Сергей М. © (2006-12-01 15:28) [34]В любом случае пара CoInitialize/CoUninitialize не помешает.
← →
Anatoly Podgoretsky © (2006-12-01 16:00) [35]> clickmaker (01.12.2006 11:34:01) [1]
> а почему не просто Break?
Что бы выполнить еще раз цикл I
← →
KyRo (2006-12-01 16:00) [36]Все сделал просто надо было выйти из цикла и вызвать Break и раставить еще по некоторым процедурам exit как тут советовали.
всем спасибо
← →
Anatoly Podgoretsky © (2006-12-01 16:02) [37]> sniknik (01.12.2006 11:48:08) [8]
> убери пока больше никто не видел...
Поздно.
← →
KyRo (2006-12-01 16:23) [38]
CoInitialize(nil);
try
.. работа с АДО, от начала и до конца ...
finally
CoUninitialize;
end;
Я щас начал добовлять эту инициализацию пишет не известный идентификатор ! В каком юните находятся эти функции ?
← →
Сергей М. © (2006-12-01 16:26) [39]ActiveX
← →
KyRo (2006-12-01 16:33) [40]ок спасибо
Страницы: 1 2 вся ветка
Форум: "Начинающим";
Текущий архив: 2006.12.17;
Скачать: [xml.tar.bz2];
Память: 0.6 MB
Время: 0.052 c