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

Вниз

Как правильно удалить поток в различных ситуациях   Найти похожие ветки 

 
Kolan ©   (2006-05-30 19:04) [0]

Здравствуйте,
 Меня мучает вопрос как коректно удалить поток. Под словом удалить подразумеваю вызвать деструктор.

Кое кокие знания у меня есть, но что я делаю не так понять не могу.

1. Вопрос номер один:
   Каким образом удаляют поток?
   - Мой ответ: Нужно вызвать метод Terminate. И незабыть выставить FreeOnTeminate в True
Так?

   - Я знаю, что Terminate просто устанавливает Terminated в True, поэтому его нужно самому проверять.

Если 1 верно(если нет, то где я не прав), то вопрос номер 2:
Как быть в следующих случаях:
а). FreeOnTerminate записано внутри Execute. Поток зоздался спящим, так и небыл "разбужен", и его надо удалить. Те до FreeOnTerminate дело даже не дошло...

б). Поток чего-то ждет. Например ф-цией WaitForSingleObject. И его надо удалить.

в). В потоке используется экземпляр ранее написанного класса. И в этом классе совершаются долгие вычисления. Сатарый класс трогать на хочется. Тогда как быть и как проверять Terminated.

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


 
TUser ©   (2006-05-30 19:07) [1]

Всегда можно вызвать TerminateThread с соотвествующим хендлом. Но грамотнее наверное будет продумать приложение так, чтобы поток корретко убивался, если его переодически приходится убивать.


 
Kolan ©   (2006-05-30 19:09) [2]


> TUser ©   (30.05.06 19:07) [1]

Убиваю обычно при закрытии приложения. И MemProof сообщает о не уничтоженных объектах(поля потока) итд...


 
TUser ©   (2006-05-30 19:10) [3]

Самому интересно - будет ли Рихтер против следующего кода

while not Terminated do begin

if WaitForSingleObject (h, 20000) <> WAIT_FAILED then begin

do something

break;

end;

end;

Вроде бы спим и ждем, но все время просыпаемся. Т.е. получается некоторый аналог sleep (20000), хотя и с использованием виндусовской синхронизации.


 
TUser ©   (2006-05-30 19:11) [4]


>
> Убиваю обычно при закрытии приложения. И MemProof сообщает
> о не уничтоженных объектах(поля потока) итд...

OnTerminate? Хотя при закрытии приложения это не важно.


 
Kolan ©   (2006-05-30 19:15) [5]

Все удаление делаю в Destoy, как всегда вообщем.


 
Пусик ©   (2006-05-31 00:00) [6]


> а). FreeOnTerminate записано внутри Execute.


Вариантов масса.

1. Устанавливай  FreeOnTerminate в конструкторе.
2. Последовательность действий:
  - Terminate
  - Resume
3. Не устанавливай FreeOnTerminate в True, а всегда используй:
  - Treminate
  - Resume
  - WaitFor
  - Free
4. Перекрой процедуру Free:
procedure TMyThread.Free(Sender: TObject);
begin
 FreeOnTerminate := True;
 Terminate;
 Resume;
 inherited;
end;


 
Пусик ©   (2006-05-31 00:03) [7]

+ жестокое уничтожение потока:

TerminateThread(MyThread.Handle,0);
MyThread.Free;


 
API ©   (2006-05-31 00:33) [8]

4. Перекрой процедуру Free:
procedure TMyThread.Free(Sender: TObject);
begin
FreeOnTerminate := True;
Terminate;
Resume;
inherited;
end;


Как мило... :)


 
atruhin ©   (2006-05-31 05:50) [9]


>  [6] Пусик ©   (31.05.06 00:00)

Девушка ну не баламутьте людей. Им же жить еще.

>  Kolan ©   (30.05.06 19:04)

Опиши конкретную проблемму если есть. Тогда подскажут. На 5 теоретических вопросов (описанных в любой книге по программированию в windows) вряд ли кто ответит. Описание работы с потоками у Рихтера занимает не менее 100 страниц, ты хочеш чтобы тебе их сюда перепечатали?

> Самому интересно - будет ли Рихтер против следующего кода
> while not Terminated do begin
> if WaitForSingleObject (h, 20000) <> WAIT_FAILED then begin

Не переживай. Увидит повешается! :). В твоем случае при нажатии на кнопку завершения программы придеться ждать 20 сек для выхода из WaitForSingleObject. Думаю более корректный вариант, для выхода из множества потоков, создать Event для выхода и ожидать его WaitForMultipleObjects


 
Пусик ©   (2006-05-31 21:22) [10]


> atruhin ©   (31.05.06 05:50) [9]
>
>
> >  [6] Пусик ©   (31.05.06 00:00)
>
> Девушка ну не баламутьте людей. Им же жить еще.


Предлагаю тебе не болтать ерундой, если нет знаний по теме топика.

> API ©   (31.05.06 00:33) [8]
> Как мило... :)


Спасибо, я тоже так думаю-)


 
tesseract ©   (2006-05-31 21:25) [11]

перекрываем  free ?????

Бакнелл рвёт оставшиеся волосы.......


 
Пусик ©   (2006-05-31 21:25) [12]


> API ©   (31.05.06 00:33) [8]


И в то же время есть еще олдин вариант - менее пугающий для новичков:

procedure TMyThread.Release;
begin
 Terminate;
 FreeOnTerminate := True;
 Resume;
end;


 
Пусик ©   (2006-05-31 21:26) [13]


> tesseract ©   (31.05.06 21:25) [11]
>
> перекрываем  free ?????


А что так волнуешься? Что в этом особенного?


 
Kolan ©   (2006-05-31 21:27) [14]

Все случаи(а, б, в) реальные.
а. Тут пример не нужен.
б. Поток ждет когда в Com порт придет информация.
в. Любой пример в стаом объекте сидит долгий цикл. Рещил завернуть в поток...


 
Пусик ©   (2006-05-31 21:33) [15]


> б. Поток ждет когда в Com порт придет информация.


Два варианта:

1. Разрушить ожидаемый объект(который указан в WaitForSingleObjec). Дальше по накатанной колее.
2. TerminateThread, затем Resume


 
Пусик ©   (2006-05-31 21:33) [16]


> 2. TerminateThread, затем Resume

+ FreeOnTerminate := True;


 
Kolan ©   (2006-05-31 21:38) [17]


> Разрушить ожидаемый объект

Я жду событие... Или вы имеете вв виду объект ядра? Просто CLoseHandle?

> TerminateThread

Как бы жестко убивать не хочется... А что разве в этом случае будет вызван деструктор?


 
Пусик ©   (2006-05-31 21:45) [18]


> Или вы имеете вв виду объект ядра? Просто CLoseHandle?

Я имел ввиду, что надо разрушить объект, дескриптор которого используется в функции ожидания. Ожидание немедленно будет прервано и поток продолжит работу. Дальше уже можно корректно завершать.


> А что разве в этом случае будет вызван деструктор?


Просто после TertminateThread вызови метод Free и все.
В 16 посте лишнее - FreeOnTerminate := True;


 
Kolan ©   (2006-06-01 13:14) [19]

Вот реальная история:
Поток заснул:
if ReadIndex >= WriteIndex then
   begin
     Suspend;
   end


Теперь закрываю приложение:

 FPackageExtractor.Terminate;
 FPackageExtractor.Resume;


По идее должен попрасть в начало Execute:
while not Terminated do (*)
 begin


Ставлб BreakPoint перед закрытием приложения на while not Terminated do.
До точки остонова дело не доходит. Все закрывается Деструктор. Естественно не вызвался.

Что я сделел не так?


 
Пусик ©   (2006-06-01 13:59) [20]


> Что я сделел не так?


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

 if ReadIndex >= WriteIndex then
 begin
    Suspend;
    if Terminated then Break;
 end;


 
Пусик ©   (2006-06-01 14:00) [21]


> По идее должен попрасть в начало Execute:


Не должен, так как выполнение продолжается с места остановки потока.


 
Kolan ©   (2006-06-01 14:02) [22]

if ReadIndex >= WriteIndex then
   begin
     Suspend;
     if Terminated then
     begin
       Break;
     end;
   end


Мой код наналогичный. До Break не добрался, проверял....

PS
Лишние begin..end"ы для отладки .....
Из лога видно что уснул и сё...


 
Пусик ©   (2006-06-01 14:03) [23]


> Из лога видно что уснул и сё...

Ключевая фраза -

> Ставлб BreakPoint перед закрытием приложения


 
Kolan ©   (2006-06-01 14:07) [24]

Ну уснул.
Перед закрытием
 FPackageExtractor.Terminate;
FPackageExtractor.Resume;


Так а где он проснется?


 
Kolan ©   (2006-06-01 14:09) [25]

while not Terminated do
 begin

   if ReadIndex >= WriteIndex then
   begin
     //
     LogManager.WriteString("Suspend");
     //
     Suspend;(*)
     if Terminated then
     begin
       //
     LogManager.WriteString("Break");
     //
       Break;
     end;
   end
   else
   begin
{...}
   end;
 end;
end;

Вот код. Если уснул в (*) и сделать Resume, то где он проснется?


 
Пусик ©   (2006-06-01 14:09) [26]


> Так а где он проснется?


Поток проснется на выполнении следующей команды после той, которую закончил выполнять перед усыплением.


 
Пусик ©   (2006-06-01 14:11) [27]

Если ты выполнял Resume, то выполнение продолжится со след. команнды.
В твоем примере это if Terminated then


 
Kolan ©   (2006-06-01 14:11) [28]


>
> Поток проснется на выполнении следующей команды после той,
>  которую закончил выполнять перед усыплением.

Ясно, почему тогда сюда не попадает?


>    //
>      LogManager.WriteString("Break");
>      //
>        Break;


 
Kolan ©   (2006-06-01 14:12) [29]

37 14:11:25 Suspend
Последняя запись в логе...


 
Пусик ©   (2006-06-01 14:12) [30]


> Ясно, почему тогда сюда не попадает?


А ты выполнил Terminate перед Resume?


 
Kolan ©   (2006-06-01 14:16) [31]

procedure TMainForm.FormDestroy(Sender: TObject);
begin
 FReadThread.Terminate;
 FComm.Free;
 FPackageComposer.Free;
 FPackageExtractor.Terminate;
 FPackageExtractor.Resume;

end;

Вот код закрытия формы.


 
begin...end ©   (2006-06-01 14:19) [32]

> Пусик ©   (31.05.06 21:26) [13]

> Что в этом особенного?

То, что Free -- он не виртуальный, вообще-то.


 
Пусик ©   (2006-06-01 14:19) [33]

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

Навесь на кнопки все и проверь.


 
Пусик ©   (2006-06-01 14:19) [34]


> begin...end ©   (01.06.06 14:19) [32]
> > Пусик ©   (31.05.06 21:26) [13]
>
> > Что в этом особенного?
>
> То, что Free -- он не виртуальный, вообще-то.


И что? Чему это может помешать?


 
begin...end ©   (2006-06-01 14:21) [35]

> Пусик ©   (01.06.06 14:19) [34]

> Чему это может помешать?

Его перекрытию.


 
Kolan ©   (2006-06-01 14:22) [36]


> У тебя просто не доходит дело до корректного закрытия доп.
>  потока - система успевает твой дополнительный поток прибить
> раньше.
>

Наконецто вот он ответ..... :). Причина ясна. ;)

Как сделать чтобы дошло?

PS
С кнопками работает.


 
Пусик ©   (2006-06-01 14:22) [37]


> begin...end ©   (01.06.06 14:21) [35]
> Его перекрытию.


Это вряд ли-)

Проверь этот код. Все нормально происходит.

procedure TMyClass.Free;
begin
 ShowMessage("!");
 inherited;
end;


 
Kolan ©   (2006-06-01 14:23) [38]


> И что? Чему это может помешать?

В этом случае произайдет закрытие метедоа...


 
Пусик ©   (2006-06-01 14:24) [39]


> Kolan ©   (01.06.06 14:22) [36]


> Как сделать чтобы дошло?


Ожидать завершения потока - метод WaitFor;


 
Пусик ©   (2006-06-01 14:25) [40]


> В этом случае произайдет закрытие метедоа...

-))



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

Форум: "Основная";
Текущий архив: 2006.07.16;
Скачать: [xml.tar.bz2];

Наверх





Память: 0.55 MB
Время: 0.01 c
1-1149022059
MZUser
2006-05-31 00:47
2006.07.16
Загрузка DLL напрямую


3-1147781026
p_evghenii
2006-05-16 16:03
2006.07.16
Помогите составить запрос


2-1151655597
Mr tray
2006-06-30 12:19
2006.07.16
Изменять выведенный текст консольного приложения


2-1151675414
Новичоккк
2006-06-30 17:50
2006.07.16
Работа с buf:pointer как с массивом char


6-1141933155
хочу все знать
2006-03-09 22:39
2006.07.16
IIS FTP и русская буква Я





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
Английский Французский Немецкий Итальянский Португальский Русский Испанский