![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Подскажите почему я не могу освободить поток [D7, XP, 2003]
KyRo © (2006-12-01 11:30:00)Я создаю поток
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 12:27:00) [21]
> А таймер мне нужен что бы сделать тайм аут на то сколько
> сервер будет ожидать ответа от клиента
а почему бы Sleep не сделать? или через события? TEvent, WaitFor
Сергей М. (2006-12-01 12:27:00) [22]
> Что это такое можно по подробнее ?
>
Подробности - в справке и msdn.
А вкратце - эти ф-ции инициализируют/деинициализируют COM-подсистему для работы в текущем код.потоке. АДО как раз и базируется на OLE/COM.
KyRo (2006-12-01 12:22:00) [23]
> CoInitialize(nil);
> try
> .. работа с АДО, от начала и до конца ...
> finally
> CoUninitialize;
> end;
Что это такое можно по подробнее ?
> это у него не сработает, т.к. до этого просто не дойдет,
> до него куча кода который уже "залипает", тут для этого
> при такой структуре нужен отдельный поток обрабатывающий
> рабочий, и вот в нем уже можно делать так. (но лучше конечно
> делать правильно ;)
тут вы не правы все отлично работает . Не могу только завершить поток.
А таймер мне нужен что бы сделать тайм аут на то сколько сервер будет ожидать ответа от клиента. И когда переходить на обработку следующего
sniknik (2006-12-01 12:16:00) [24]> Имеете ввиду вот этот цикл ? Поставить после него проверку на Terminated
> и если есть то Exit ? Я правильно понял ?
нет. я имел ввиду первый показанный цикл, и не после него а в нем. разница однако!
> {Запускаем опрос}
> For i := 0 to ATML.Count -1 do
> begin
> {Запускаем сервер}
> ServerS.ServerType:=stNonBlocking;
> ServerS.Port:=50018;
> ServerS.Active:=True;
> и.т.д
но после показан код который разбирать совсем не хочется, его проще переделать.
Сергей М. (2006-12-01 12:16:00) [25]
> sniknik © (01.12.06 12:13) [15]
> это у него не сработает, т.к. до этого просто не дойдет,
> до него куча кода который уже "залипает"
Это понятно.
Но, согласись, грамотная организация такого цикла (если он необходим, а он при данной логике действительно необходим) - один из ключевых моментов в сквозной логике.
sniknik (2006-12-01 12:13:00) [26]Сергей М. © (01.12.06 12:07) [12]
> while not Terminated and GetMessage(Msg, 0, 0, 0) do
> DispatchMessage(Msg);
это у него не сработает, т.к. до этого просто не дойдет, до него куча кода который уже "залипает", тут для этого при такой структуре нужен отдельный поток обрабатывающий рабочий, и вот в нем уже можно делать так. (но лучше конечно делать правильно ;)
Сергей М. (2006-12-01 12:11:00) [27]Ну и еще один крайне важный момент:
CoInitialize(nil);
try
.. работа с АДО, от начала и до конца ...
finally
CoUninitialize;
end;
Выделенное жирным обязательнодля исполнения в каждом доп.потоке, в котором осуществляется работа с АДО (и не только с ним)
В противном случае будет возбуждено исключение и твой поток "залипнет", поскольку в нем нет общей обработки исключений.
sniknik (2006-12-01 12:09:00) [28]> Я не обращаюсь в всл Application.ProcessMessages ; для того что бы работали события таймера ,клиента и сервера которые
> функционируют в этом потоке
да? покажи выборку сообщений своего потока, и зачем одноименно назвал (Application) обрабатывающий поток с основным?...
сдается мне мил человек, что ты ... эта, в кучу все смешал, и пользуешься без разбора в потоке глобальными таймерами/переменными, из потока их только стартуешь.
Сергей М. (2006-12-01 12:07:00) [29]
> Я не обращаюсь в всл Application.ProcessMessages
Здрасть-приехали !
Application - это что по-твоему ? Не VCL-объект, надо понимать ?
> для того что бы работали события таймера ,клиента и сервера
> которые функционируют в этом потоке
Насчет таймера в код не вникал, но более чем уверен - он там нафиг не нужен.
По поводу же клиента и сервера тебе, как помнится, уже приводили код:
while not Terminated and GetMessage(Msg, 0, 0, 0) do
DispatchMessage(Msg);
И все ! И никаких Application.ProcessMessages тут не нужно ! Все при этом расчудесно работает)
clickmaker (2006-12-01 11:58:00) [30]
> Залипает на строке которй я его пытаюсь освободить
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
KyRo (2006-12-01 11:54:00) [31]
> В коде куча грубых ошибок.
> Проще все переписать с нуля, чем их исправлять.
Это легче всего сказать !!
> Насколько мне помнится, ты уже получал граблями за обращение
> к VCL-компонентам в доп.потоке, и теперь вновь на них наступаешь.
>
> > Application.ProcessMessages ;
> в потоке ????? убери пока больше никто не видел...
Я не обращаюсь в всл Application.ProcessMessages ; для того что бы работали события таймера ,клиента и сервера которые функционируют в этом потоке
KyRo (2006-12-01 11:52:00) [32]
> 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 ? Я правильно понял ?
> ну как вариант, можно в отладчике прогнать. Посмотреть,
> на какой строке залипает
Залипает на строке которй я его пытаюсь освободить
sniknik (2006-12-01 11:48:00) [33]> Application.ProcessMessages ;
в потоке ????? убери пока больше никто не видел...
Сергей М. (2006-12-01 11:48:00) [34]
> KyRo
В коде куча грубыхошибок.
Проще все переписать с нуля, чем их исправлять.
p.s.
Насколько мне помнится, ты уже получал граблями за обращение к VCL-компонентам в доп.потоке, и теперь вновь на них наступаешь.
sniknik (2006-12-01 11:46:00) [35][1] +
> из за чего это может происходить ?
в цикле, который выполняется долго, нет проверки на Terminated и выхода если установлен, вот он его до конца и прокручивает.
++
ATML:=TStringList.Create;
try
//все остальное сдесь
//например
if LoadATMList(ATML) = False then Break; //или Exit если вдруг вложенных циклов станет больше одного, и нужно выйти а Break этого уже позволит.
....
finally
ATML.Free;
end;
clickmaker (2006-12-01 11:45:00) [36]ну как вариант, можно в отладчике прогнать. Посмотреть, на какой строке залипает
KyRo (2006-12-01 11:42:00) [37]
> Причина в "и. т. д."
:)
Держите расшифровку (весь 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;
KyRo (2006-12-01 11:40:00) [38]
> а почему не просто Break?
Можно и Break? не спорю но тогда надо освободить сервер и клиент или они вместе с потоком освободятся автоматом когда я его уничтожу?
> И зачем свойства в цикле каждый раз по новой назначать?
Свойства чего сервера ? Если да то для разных клиентов разные параметры.
С (2006-12-01 11:39:00) [39]Причина в "и. т. д."
clickmaker (2006-12-01 11:34:00) [40]
> if LoadATMList(ATML) =False
> then
> begin
> ATML.Free;
> Terminate;
> end;
а почему не просто Break? И зачем свойства в цикле каждый раз по новой назначать?