Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.01.09;
Скачать: [xml.tar.bz2];

Вниз

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

 
Ил_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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.011 c
1-25306
Мефодий
2003-12-22 22:09
2004.01.09
Эмуляция клика мыши в другой прогроамме


4-25636
Fox Mulder
2003-11-07 06:31
2004.01.09
Скины


14-25543
dDan
2003-12-18 16:17
2004.01.09
Пара простеньких вопросов


3-25264
NewD
2003-12-10 12:08
2004.01.09
DefaultExpression - не работает судя по всему. Что делать ?


3-25229
h0use
2003-12-10 15:32
2004.01.09
Как получить внесенные изменения из DBGrid





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский