Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.01.09;
Скачать: CL | DM;

Вниз

Проблема с остановкой потока   Найти похожие ветки 

 
Ил_204   (2003-12-22 10:21) [0]

Есть поток:
procedure TMyThread.Execute;
var
i: integer;
begin
FreeOnTerminate := true;

for i := 1 to 10 do begin
Sleep(100);
beep;
end;

// FreeAndNil(self);
end;

Есть ф-ция запуска потока:
procedure TForm1.Button1Click(Sender: TObject);
var
MyThread: TMyThread;
i: integer;
begin
MyThread := TMyThread.Create(False);

for i := 1 to 1000 do begin
if not Assigned(MyThread) then begin
ShowMessage("free");
exit;
end;

sleep(10);
end;

ShowMessage("not free");
end;

Вопрос в следующем, почему не работает конструкция
not Assigned(MyThread)?
Даже FreeAndNil(self) перед завершением потока не спасает.


 
Bart   (2003-12-22 10:27) [1]

Assigned в данном примере понятия не иммет каково состояние переменной MyThread. Т.к. поток содается CreateSuspend = False, да еще и в теле написано FreeOnTerminate = True.

Все поток запущен, общение с ним может осщуствляться только через сообщения.


 
Digitman ©   (2003-12-22 10:29) [2]


> почему не работает конструкция
> not Assigned(MyThread)?


потому что в твоем коде переменной MyThread нигде nil не присваивается, вот она все время и остается Assigned

в случае использования FreeOnTerminate = True вероятным решением будет назначение обработчика события TThread.OnTerminate() , в теле которого как раз и уместно выполнить MyThread := nil;


 
Ил_204   (2003-12-22 10:34) [3]

2Bart: Дело не в общении с потоком, нужно лишь отследить момент когда его код закончится и он выгрузиться из памяти.

2Digitman: Странно почему FreeAndNil(Self) в конце не работал?! Сейчас буду пробовать Ваш вариант.


 
Ил_204   (2003-12-22 10:36) [4]

2Digitman: В обработчике TThread.OnTerminate() не может быть MyThread := nil, только self := nil. Так?


 
Digitman ©   (2003-12-22 10:41) [5]


> Странно почему FreeAndNil(Self) в конце не работал?!


потому что это чушь


> В обработчике TThread.OnTerminate() не может быть MyThread
> := nil, только self := nil. Так?


не так.


> нужно лишь отследить момент когда его код закончится и он
> выгрузиться из памяти


откажись от FreeOnTerminate = True и выполняй

MyThread := TMyThread.Create(False);
MyThread.WaitFor; // ждем фактического завершения потока
FreeAndNil(MyThread); // разрушаем объект и обнуляем ссылку


 
Ил_204   (2003-12-22 10:46) [6]

А ежели поток повиснет?


 
Digitman ©   (2003-12-22 10:52) [7]


> А ежели поток повиснет?


с чего бы ему "повиснуть" ?
еслим логика в теле Execute корректна и предусматривает все возможные ситуации, которые могут повлиять на своевременное и безошибочное завершение потока ?


 
Bart   (2003-12-22 10:56) [8]

я собственно об этом и говорю, на Free потока послать сообщение основному потоку.
А циклом проверять - как-то не красиво.


 
Ил_204   (2003-12-22 11:02) [9]

2Digitman: в потоке используется код чужих dll со всеми вытекающими...

2Bart: громоздко как-то получается :(


 
Ил_204   (2003-12-22 11:10) [10]

Конструкция была приведена к следующему виду:
procedure TForm1.Button1Click(Sender: TObject);
var
MyThread: TMyThread;
i: integer;
begin
MyThread := TMyThread.Create(False);

for i := 1 to 500 do begin
if MyThread.IsTerminated then begin
ShowMessage("free");
FreeAndNil(MyThread);
exit;
end;

Label1.Caption := IntToStr(i);
Application.ProcessMessages;
sleep(10);
end;

ShowMessage("not free");
end;
...
TMyThread = class(TThread)
private
fIsTerminated: boolean;
procedure MyTerminate(Sender: TObject);
protected
procedure Execute; override;
public
property IsTerminated: boolean read fIsTerminated;
end;
...
procedure TMyThread.Execute;
var
i: integer;
begin
fIsTerminated := false;
OnTerminate := MyTerminate;

FreeOnTerminate := false;

for i := 1 to 10 do begin
Sleep(100);
beep;
end;
end;
...
procedure TMyThread.MyTerminate(Sender: TObject);
begin
fIsTerminated := true;
end;
...

Что скажете, есть замечания?


 
Digitman ©   (2003-12-22 11:10) [11]


> Ил_204


и что ? ты считаешь что осн.поток должен постоянно "пасти" дополнительные на предмет, "зависли" они или "не зависли" ?

дурней не придумаешь)

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


 
Ил_204   (2003-12-22 11:16) [12]

Нафик не уперлось постоянно его "пасти".

Основная идея: при завершении потока, если тот не умирает, то выждать заданное число таймаутов и выдать пользователю сообщение об ошибке. Далее по ситуации.


 
Digitman ©   (2003-12-22 11:17) [13]

какой у тебя вообще критерий оценки факта "зависания" потока ?
откуда тебе знать, сколько точно времени требуется поточной ф-ции для ее выполнения ? время это зависит от множества факторов !


 
Digitman ©   (2003-12-22 11:20) [14]


> выждать заданное число таймаутов


откуда тебе ЗАРАНЕЕ знать, чему равно это число ?
а если потоку требуется на долю миллисекунды больше для корректного завершения, то что ? он разве "завис" ? да ты просто недождался !


 
Ил_204   (2003-12-22 11:22) [15]

определяется пользователем в настроечном файле.


 
Digitman ©   (2003-12-22 11:27) [16]


> Ил_204


))

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


 
Bart   (2003-12-22 11:28) [17]

А неужели есть необходимость знать когда поток закончит работу? Если это обработка - запускай ее и забывай, только логи не забывай писать.
Какая конечная цель?


 
Digitman ©   (2003-12-22 11:40) [18]


> Ил_204


"рисую" последствия твоей логики , ч.н., "на огурцах" :

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

- после старта потока ты берешь из конфиг.файла число = 5 сек (которое учтановил сам юзер перед стартом приложения, причем - от балды) и ждешь эти 5 сек на предмет факта завершения потока

- рельно вызванная в потоке DLL-ф-ция на сей момент отработает до конца не за 5 сек, а за 10 сек, через которые следовало бы ожидать нормального завершения записи в файл всей необх. по расчетам инф-ции

- по истечении 5 сек в лучшем случае ты выдаешь юзеру предупреждение и за сим успокаиваешься (хуже, если тут же принудительно терминируешь поток)

в результате в лучшем случае ты змучаешь юзера дурацкими предупреждениями (юзер-то видит, что на самом деле ожидаемый файл появился и корректен !!), в худшем - юзер будет в панике, потому что результирующий файл по каким-то непонятным ему причинам имеет совершенно неожидаемое, "огрызкообразное" содержимое !


 
Ил_204   (2003-12-22 11:44) [19]

Поток работает с устройством. Ситуация завершения потока происходит при принудительной остановке устройства(сам поток+драйвера+железка) администратором сервера. Ясное дело, что это должно произойти за конечное время, определенное админом. Продолжительность периода зависит от типа оборудования и вибирается САМИМ администратором.
Естественно, с первого раза оптимальную задержку не поставишь, но речь идет не о настройке, а об эксплуатации.


 
mrcat ©   (2003-12-22 11:48) [20]

Ил_204 (22.12.03 11:44) [19]
>Поток работает с устройством.

А нельзя ли этим устройством, посылать потоку сигнал завершения ?


 
Ил_204   (2003-12-22 11:50) [21]

Устройства разных типов. Никак... :(


 
Digitman ©   (2003-12-22 11:50) [22]


> Ил_204


и что ? "устройство" не имеет асинхр.режима взаимодействия с ним ? и никаких тайм-аутов нет в помине ?


 
alex_***   (2003-12-22 11:50) [23]

или поток пинговать и в случае зависания Terminate() ?


 
Digitman ©   (2003-12-22 11:52) [24]


> Ил_204


ты вообще в состоянии вразумительно описать, ЧЕМ вызвана необходимость вынесения логики работы с дивайсом в доп.код.поток ?


 
Digitman ©   (2003-12-22 11:54) [25]


> alex_*** (22.12.03 11:50) [23]
> или поток пинговать


"пинговать" - сильно сказано)

даже не рискну полюбопытствовать, какое отношение Packet INternet Goopher имеет к код.потоку)


 
alex_***   (2003-12-22 11:55) [26]

[23] : Только надо корректно определять зависания, учитывая картину [18] ))


 
alex_***   (2003-12-22 11:56) [27]

ну блин, это я иносказательно. Сообщения посылать, я имел ввиду.


 
Digitman ©   (2003-12-22 12:01) [28]


> Сообщения посылать, я имел ввиду


кому ? потоку ? а если он в это время корректно исполняет некий блок.вызов и попросту занят совершенно иным делом ?

PostThreadMessage ? вернет True - поток-то существует ..
Post/SendMessage ? окно нужно создавать, а надо ли оно ?

ну,предположим, создали окно, вызвали SendMessageNotify(), получили отлуп по тайм-айту, и что ? сие есть разве факт "зависания" ?!


 
Ил_204   (2003-12-22 12:10) [29]

2Digitman: 255 устройств. все в одном потоке разруливать?


 
Digitman ©   (2003-12-22 12:23) [30]


> 255 устройств. все в одном потоке разруливать?


да хоть 25000 !

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

а транспорт, будучи упомянутым, бывает синхронным и асинхронным, о чем ты ни слова не сказал


 
Ил_204   (2003-12-22 12:26) [31]

Всем огромное спасибо за помощь.



Страницы: 1 вся ветка

Текущий архив: 2004.01.09;
Скачать: CL | DM;

Наверх




Память: 0.55 MB
Время: 0.028 c
4-25658
kryn
2003-11-06 10:48
2004.01.09
как при помощи DELPHI удалить папку вместе с файлами?


1-25437
MV
2003-12-23 18:05
2004.01.09
А можно ли, отловив в обработчике формы сообщение, скажем WM_PAIN


14-25533
Valya(Crazy)
2003-12-19 11:22
2004.01.09
Как ускорить движок на OpenGl


14-25514
}|{yk
2003-12-16 11:33
2004.01.09
Можно ли заставить Builder пользоваться делфийским дебуггером?


3-25263
3LoBit
2003-12-08 14:30
2004.01.09
Странное выполнение OnCalcFields в TSQLQuery