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

Вниз

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

 
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;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.033 c
2-1151559279
lobach
2006-06-29 09:34
2006.07.16
Расположение


2-1151419117
learner
2006-06-27 18:38
2006.07.16
Уничтожение класса в классе


15-1150282525
dexis
2006-06-14 14:55
2006.07.16
Что-та типа splitterа, раскрывающий/скрывающий панель оним кликом


8-1137709538
Nailspb
2006-01-20 01:25
2006.07.16
Drag &amp; Drop


15-1150434472
pavel_guzhanov
2006-06-16 09:07
2006.07.16
непонятная проблема с компом... наконец решил спросить