Форум: "Начинающим";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
ВнизКак корректно удалить экземпляр TThread из TList? Найти похожие ветки
← →
kotyara12 (2010-05-12 21:22) [0]Может и друрацкий вопрос, но я уже совсем запутался: я создаю несколько независимых потоков с FreeOnTerminate = True и помещаю их в экземпляр TList. Что произойдет, если поток отработает до конца и удалиться из памяти? Произойдет ли при этом удаление соответствущего указателя из TList или нужно как-то по другому удалить отработавший поток?
← →
DVM © (2010-05-12 21:37) [1]
> Что произойдет, если поток отработает до конца и удалиться
> из памяти?
Поток отработает, экземпляр TThread будет разрушен. Из TList ссылка на уже несуществующий экземпляр TThread само собой удалена не будет.
Вообще на мой взгляд кривоватый какой то подход ты выбрал.
← →
kotyara12 (2010-05-12 21:49) [2]
> Вообще на мой взгляд кривоватый какой то подход ты выбрал
Как тогда лучше поступить? Подскажи, если не в лом....
← →
kotyara12 (2010-05-12 21:51) [3]Если при создании потока поставить, FreeOnTerminate = False, то отработавший поток останется в памяти до полного удаления списка, а отследить "извне", отработал поток или еще нет - у меня не получилось.
← →
Anatoly Podgoretsky © (2010-05-12 22:01) [4]> kotyara12 (12.05.2010 21:51:03) [3]
OnTerminate
← →
kotyara12 (2010-05-12 22:15) [5]
> Anatoly Podgoretsky © (12.05.10 22:01) [4]
> > kotyara12 (12.05.2010 21:51:03) [3]OnTerminate
А не лучше в таком случае в поток при создании передать указатель на List и в Destroy вызвать fList.Remove(Self)?
← →
DVM © (2010-05-12 22:16) [6]
> kotyara12 (12.05.10 21:49) [2]
FreeOnTerminate = True - это крайне глюконосная фича, которой на мой взгляд лучше избегать.
Лучше собственноручно отслеживать завершение работы потока и уничтожать объекты TThread.
← →
Rouse_ © (2010-05-12 22:51) [7]
> DVM © (12.05.10 22:16) [6]
> FreeOnTerminate = True - это крайне глюконосная фича, которой
> на мой взгляд лучше избегать.
> Лучше собственноручно отслеживать завершение работы потока
> и уничтожать объекты TThread.
На основе чего сделан столь сочный вывод? Нет, я конечно понимаю что лучше взять готовый велосипед и немножно его погнуть (читай написать заново уже написанный код), но...?
← →
Игорь Шевченко © (2010-05-12 23:06) [8]
> FreeOnTerminate = True - это крайне глюконосная фича, которой
> на мой взгляд лучше избегать.
аргументы будут ? :)
← →
kotyara12 (2010-05-12 23:10) [9]На данный момент сделал так:
Поток задания:
constructor TAuFpdThread.Create(...);
begin
inherited Create(True);
FreeOnTerminate := True;
......
Основной поток:
TaskItem := TAuFpdThread.Create(...);
TaskItem.OnTerminate := TerminateTask;
fTaskList.Add(TaskItem);
procedure TFpdService.TerminateTask(Sender: TObject);
begin
fTaskList.Remove(Sender);
end;
Думаю, будет работать... завтра проверим :-)
← →
Rouse_ © (2010-05-12 23:18) [10]DVM, я немножко разовью свой предыдущий пост. Сразу предупреждаю - все естественно мое ИМХО.
TThread достаточно кривовато сделанный класс, прежде всего ествественно из-за механизма синхронизации. Мне очень не понятно почему синхронизация нити в классе TThread делается всегда с главной нитью приложения, а не с той нитью из которой был создан данный обьект. Сразу естественно наступаем на грабли в рамках сервисов - главная нить приложения отвечает за общение службы с SCM и соответственно 99.9 процентов времени находится в суспенде.
Что остается - остается только пресловутый FreeOnTerminate, который позволяет нам не заморачиваться на написание кода типа WaitForSingleObject, а просто создать нить - передать ей задачу и забыть.
Если мы отказываемся от данной фичи, то мы имеем на руках:
1: необходимость собственной синхронизации
2. необходимость самостоятельного отслеживания времени жизни нити
Вопрос: зачем тогда он вообще нужен класс этот без использования FreeOnTerminate, если стандартные АПИ гораздо качественней выполняют все описанное? :)
← →
antonn © (2010-05-12 23:18) [11]там Synchronize() случаем не нужен?
← →
Loginov Dmitry © (2010-05-12 23:21) [12]
> Думаю, будет работать... завтра проверим :-)
Вместо TList в таких случаях следует использовать TThreadList, иначе глюки "непонятной" природы не заставят себя ждать.
← →
Eraser © (2010-05-12 23:23) [13]> [10] Rouse_ © (12.05.10 23:18)
> Вопрос: зачем тогда он вообще нужен класс этот без использования
> FreeOnTerminate, если стандартные АПИ гораздо качественней
> выполняют все описанное? :)
кстати, всегда интересовал такой вопрос - где правильно уничтожать дескриптор созданного через Begin/CreateThread потока? )
← →
kotyara12 (2010-05-12 23:23) [14]
> Rouse_ ©
это как раз и есть сервис...
← →
Rouse_ © (2010-05-12 23:24) [15]
> Eraser © (12.05.10 23:23) [13]
Ествесвенно по завершении оного :)
← →
Loginov Dmitry © (2010-05-12 23:24) [16]
> Что остается - остается только пресловутый FreeOnTerminate,
> который позволяет нам не заморачиваться на написание кода
> типа WaitForSingleObject, а просто создать нить - передать
> ей задачу и забыть.
Вот-вот, передать задачу и забыть. И этом вся прелесть!
← →
Rouse_ © (2010-05-12 23:24) [17]
> kotyara12 (12.05.10 23:23) [14]
>
>
> > Rouse_ ©
>
> это как раз и есть сервис...
Тогда ололо - готовь голову к шишкам от граблей :)
← →
kotyara12 (2010-05-12 23:27) [18]
> Вместо TList в таких случаях следует использовать TThreadList
пробовал. наткнулся на следующие грабли: при останвке сервиса останавливаю все потоки задач:
with fTaskList.LockList do
begin
try
for i := 0 to Count - 1 do
TThread(Item[i]).Terminate;
TThread(Item[i]).WaitFor; <- ЗДЕСЬ ЗАВИСАЕТ НАМЕРТВО, приходится снимать процесс
finally
fTaskList.UnlockList;
end
end
← →
Rouse_ © (2010-05-12 23:30) [19]В рамках сервиса так нельзя - будет дедлок. - Срывай через терминирование.
← →
Rouse_ © (2010-05-12 23:31) [20]Имеется ввиду через апи TerminateThread()
← →
DVM © (2010-05-12 23:31) [21]
> Rouse_ © (12.05.10 22:51) [7]
> Игорь Шевченко © (12.05.10 23:06) [8]
Аргументы чего я должен привести?
Проблема то не в самом FreeOnTerminate = True, а в том, что его применение без особой на то необходимости и без тщательного контроля происходящего принесет только проблемы. Есть некоторая неочевидность того, что происходит при его применении и как пользоваться этим свойством.
← →
Eraser © (2010-05-12 23:32) [22]> [15] Rouse_ © (12.05.10 23:24)
да, и потому FreeOnTerminate наше все, т.к. частенько контроль этих самых дескрипторов выливается в куда более не тривиальную задачу, чем сам код потока.
а в случае чего всегда можно FreeOnTerminate отключить, убрать обработчик OnTerminate и дождаться завершения потока через WaitFor.
ну собственно я это не вам рассказываю, а топикстартеру )
← →
kotyara12 (2010-05-12 23:32) [23]
> Rouse_ © (12.05.10 23:31) [20]
> Имеется ввиду через апи TerminateThread()
спс... щас покопаемся...
← →
Eraser © (2010-05-12 23:33) [24]> [18] kotyara12 (12.05.10 23:27)
OnTerminate срабатывает? где в этот момент висит TThread(Item[i])?
← →
Rouse_ © (2010-05-12 23:34) [25]
> дождаться завершения потока через WaitFor.
Не получиться опять-же, дедлок из-за неочевидного механизма синхронизаии в очень многих случаях :)
← →
DVM © (2010-05-12 23:35) [26]
> kotyara12 (12.05.10 23:27) [18]
> with fTaskList.LockList do
> begin
> try
> for i := 0 to Count - 1 do
> TThread(Item[i]).Terminate;
> TThread(Item[i]).WaitFor; <- ЗДЕСЬ ЗАВИСАЕТ НАМЕРТВО,
> приходится снимать процесс
> finally
> fTaskList.UnlockList;
> end
> end
Ты свое глюконосное FreeOnTerminate := true убери и не будет виснуть.
← →
Loginov Dmitry © (2010-05-12 23:35) [27]
> пробовал. наткнулся на следующие грабли: при останвке сервиса
> останавливаю все потоки задач:
Правильно зависает. Зато ведь понятно из-за чего!
Лобовой метод обхода:with fTaskList.LockList do
begin
try
for i := 0 to Count - 1 do
TThread(Item[i]).Terminate;
finally
fTaskList.UnlockList;
end
end;
while True do
begin
with fTaskList.LockList do
try
ACount := Count;
finally
fTaskList.UnlockList;
end;
if ACount = 0 then
Break
else
begin
Sleep(10);
//Application.ProcessMessages();
end;
end;
← →
DVM © (2010-05-12 23:36) [28]Убивать потоки принудительно через TerminateThread() недопустимо.
← →
Eraser © (2010-05-12 23:37) [29]> [26] DVM © (12.05.10 23:35)
кстати да, тут или FreeOnTerminate := true убрать, или WaitFor;
> [25] Rouse_ © (12.05.10 23:34)
так и не чего синхронайз использовать, imho. за редчайшим исключением можно обойтись без него и даже более грамотно выйдет.
← →
Rouse_ © (2010-05-12 23:38) [30]
> DVM © (12.05.10 23:36) [28]
>
> Убивать потоки принудительно через TerminateThread() недопустимо.
>
При завершении приложения? С чего бы это?
И кстати, ты так и не привел аргументов в пользу отсутствия FreeOnTerminate
← →
Rouse_ © (2010-05-12 23:39) [31]
> Eraser © (12.05.10 23:37) [29]
> так и не чего синхронайз использовать, imho. за редчайшим
> исключением можно обойтись без него
Я бы кнечто тоже за, но ты реальзацию метода WaitFor смотрел? :)
Особливо вызов метода CheckSynchronize в рамках сервиса?
← →
Loginov Dmitry © (2010-05-12 23:41) [32]
> Имеется ввиду через апи TerminateThread()
Превосходный совет, нет слов :)
> Проблема то не в самом FreeOnTerminate = True, а в том,
> что его применение без особой на то необходимости и без
> тщательного контроля происходящего принесет только проблемы.
> Есть некоторая неочевидность того, что происходит при его
> применении и как пользоваться этим свойством.
Тут вроде как всего 2 варианта: либо мы ставим FreeOnTerminate = False, и отвечаем на уничтожение, либо ставим FreeOnTerminate = True, и дальше ни коем образом к объекту потока не обращаемся (ибо он может оказаться уничтожен в любой момент). Кстати да, есть поводы для глюков, как и со Suspend. Может подать идейку чтоб и FreeOnTerminate сделали deprecated =)
← →
DVM © (2010-05-12 23:42) [33]
> Rouse_ © (12.05.10 23:38) [30]
> При завершении приложения? С чего бы это?
Не, я не про завершение конечно. Хотя...
Я привык и при завершении пытаться все по-человечески все закрывать.
← →
Loginov Dmitry © (2010-05-12 23:45) [34]
> > Убивать потоки принудительно через TerminateThread() недопустимо.
>
> >
>
> При завершении приложения? С чего бы это?
С того, что поток в этот момент занят записью какого-нибудь файла на жесткий диск. Убъешь поток, получишь пол-файла или вообще ничего.
← →
Eraser © (2010-05-12 23:47) [35]> [31] Rouse_ © (12.05.10 23:39)
> Я бы кнечто тоже за, но ты реальзацию метода WaitFor смотрел?
> :)
ух, ну и накрутили же они, я то наивно пологал, что там честный WaitForSingleObject ;-)
оно кстати так и есть, если GetCurrentThreadID <> MainThreadID, что для сервиса чаще всего и бывает.if GetCurrentThreadID = MainThreadID then
begin
WaitResult := 0;
H[1] := SyncEvent;
repeat
{ This prevents a potential deadlock if the background thread
does a SendMessage to the foreground thread }
if WaitResult = WAIT_OBJECT_0 + 2 then
PeekMessage(Msg, 0, 0, 0, PM_NOREMOVE);
WaitResult := MsgWaitForMultipleObjects(2, H, False, 1000, QS_SENDMESSAGE);
CheckThreadError(WaitResult <> WAIT_FAILED);
if WaitResult = WAIT_OBJECT_0 + 1 then
CheckSynchronize;
until WaitResult = WAIT_OBJECT_0;
end else WaitForSingleObject(H[0], INFINITE);
← →
Loginov Dmitry © (2010-05-12 23:52) [36]Самое надежное средство: BeginThread. Никогда не подводит :)
← →
Игорь Шевченко © (2010-05-13 00:05) [37]DVM © (12.05.10 23:31) [21]
> Аргументы чего я должен привести?
Очевидно глючности конструкции FreeOnTerminate = true, вроде речь шла об этом.
> Проблема .. в том,
> что его применение без особой на то необходимости и без
> тщательного контроля происходящего принесет только проблемы.
> Есть некоторая неочевидность того, что происходит при его
> применении и как пользоваться этим свойством.
У нас говорят проще: дай дураку член стеклянный, он и член разобьет, и руки порежет.
Какая нафиг неочевидность - открываешь classes.pas и все, как на ладони.
Потоками вообще надо слегка с умом пользоваться, там и без FreeOnTerminate хватает граблей.
← →
kotyara12 (2010-05-13 00:05) [38]Спасибо всем за комментарии... начинаю понемногу въезжать в ситуацию.
Насколько я понял из реализации TThread обработка OnTerminate (например, удаление потока из списка) и FreeOnTerminate = True друг другу не мешают... А вызовfTaskList.Remove(Sender);
из OnTerminate при FreeOnTerminate = False не уничтожит поток...
var
FreeThread: Boolean;
begin
try
if not Thread.Terminated then
try
Thread.Execute;
except
Thread.FFatalException := AcquireExceptionObject;
end;
finally
FreeThread := Thread.FFreeOnTerminate;
Result := Thread.FReturnValue;
Thread.DoTerminate; <- обработка OnTerminate
Thread.FFinished := True;
SignalSyncEvent;
if FreeThread then Thread.Free; <- FreeOnTerminate = True
или я ошибаюсь?
← →
DVM © (2010-05-13 00:07) [39]
> Rouse_ © (12.05.10 23:38) [30]
> И кстати, ты так и не привел аргументов в пользу отсутствия
> FreeOnTerminate
1) Мы всегда знаем, сколько у нас живых экземляров объекта TThread
2) Мы всегда можем быть уверены в том что в конкретный момент конкретный экземпляр жив.
3) Мы можем корректно закрыть все ресурсы потоков и сами потоки и затем уничтожить объекты TThread просто вызовом Terminate и WaitFor.
Лучше бы кто нибудь мне привел реальную пользу от FreeOnTerminate
← →
DVM © (2010-05-13 00:09) [40]
> Игорь Шевченко © (13.05.10 00:05) [37]
> Очевидно глючности конструкции FreeOnTerminate = true, вроде
> речь шла об этом.
Речь не о глючности конструкции, а о ее глюконосности. Разные вещи.
Страницы: 1 2 3 вся ветка
Форум: "Начинающим";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
Память: 0.55 MB
Время: 0.091 c