Текущий архив: 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.55 MB
Время: 0.01 c