Форум: "Начинающим";
Текущий архив: 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, вроде
> речь шла об этом.
Речь не о глючности конструкции, а о ее глюконосности. Разные вещи.
← →
DVM © (2010-05-13 00:12) [41]
> kotyara12 (13.05.10 00:05) [38]
я не понимаю, зачем тебе все эти пляски с бубном вокруг FreeOnTerminate = true, когда Terminate + WaitFor + FreeOnTerminate = false позволяют прекрасно все контролировать? Один хрен у тебя есть список.
← →
Игорь Шевченко © (2010-05-13 00:12) [42]DVM © (13.05.10 00:07) [39]
> Лучше бы кто нибудь мне привел реальную пользу от FreeOnTerminate
ну давай я тебе длинно и непоследовательно расскажу про задачи своей предметной области, про алгоритмы их решения, возможную реализацию этих алгоритмов, и в качестве одной из наглядных иллюстраций будет конструкция с несколькими дополнительными потоками, у которых свойство FreeOnTerminate установлено в True. Ты это сочтешь за реальную пользу или без рассказа поверишь на слово ?
Польза простая - выстрелил, забыл, оно дальше само полетело и поразило.
← →
Игорь Шевченко © (2010-05-13 00:14) [43]DVM © (13.05.10 00:09) [40]
> Речь не о глючности конструкции, а о ее глюконосности. Разные
> вещи.
Я понял, considered harmhul. А в Борландовских Demos об этом не знали. Изучайте Demos - источник знаний.
← →
kotyara12 (2010-05-13 00:15) [44]
> 3) Мы можем корректно закрыть все ресурсы потоков и сами
> потоки и затем уничтожить объекты TThread просто вызовом
> Terminate и WaitFor.
WaitFor уничтожит поток?
← →
DVM © (2010-05-13 00:19) [45]
> Игорь Шевченко © (13.05.10 00:12) [42]
> Польза простая - выстрелил, забыл, оно дальше само полетело
> и поразило.
Наверное оно так. Пока программа работает и закрываться не собирается. Но вот она собралась закругляться. И что у нас там летает контролировать сложно. Хорошо если оно там умрет своей смертью вовремя без последствий.
Не, как хотите, но такой подход не по мне.
← →
Eraser © (2010-05-13 00:20) [46]> [44] kotyara12 (13.05.10 00:15)
нет, потом еще Free нужно вручную.
← →
kotyara12 (2010-05-13 00:21) [47]
> я не понимаю, зачем тебе все эти пляски с бубном вокруг
> FreeOnTerminate = true, когда Terminate + WaitFor + FreeOnTerminate
> = false позволяют прекрасно все контролировать? Один хрен
> у тебя есть список.
да к тому, что тогда нужно поток по завершнию работы (нормальному завершению в точ числе и в основном) удалить из памяти.
запускаю я поток, он выполняет свою задачу, в обработчике OnTerminate - удаляет себя из списка. А в памяти он останется. И в OnTerminate делать Sender.Free я думаю некорректно.
Terminate + WaitFor нужен только для завершения работы сервиса. а сервис должен крутиться месяцы напролет
← →
Eraser © (2010-05-13 00:21) [48]> [39] DVM © (13.05.10 00:07)
> Лучше бы кто нибудь мне привел реальную пользу от FreeOnTerminate
любой многопоточный сервер, например, named pipe.
← →
DVM © (2010-05-13 00:21) [49]
> kotyara12 (13.05.10 00:15) [44]
> WaitFor уничтожит поток?
нет
Последовательность такова:
1) Teminate - сообщаем потоку чтобы он закруглялся. Он должен закругляться по этому сигналу, постоянно проверяя этот флаг.
2) WaiFor - ждем пока поток закруглится. Если он не сможет, то мы висим!
3) Free объекту потока. Теперь можно точно и со спокойной душой.
← →
DVM © (2010-05-13 00:23) [50]
> Eraser © (13.05.10 00:21) [48]
> любой многопоточный сервер
не лучше ли держать пулы потоков и не тормошить систему постоянно их созданием уничтожением?
← →
kotyara12 (2010-05-13 00:25) [51]а не проще, если он сам себя удалит. а в OnTerminate удалит свой линк из списка?
а при завершении сервиса наверное можно использовать метод предложенный Loginov Dmitry, правда я его мальнько переработал:
with fTaskList.LockList do
begin
try
for i := 0 to Count - 1 do
TThread(Items[i]).Terminate;
finally
fTaskList.UnlockList;
end;
end;
repeat
with fTaskList.LockList do
begin
try
TaskCount := Count;
finally
fTaskList.UnlockList;
end;
end;
if TaskCount > 0 then Sleep(10);
until TaskCount = 0;
← →
Eraser © (2010-05-13 00:26) [52]> [50] DVM © (13.05.10 00:23)
ну а если сервер не супер-загруженный, когда ни когда создается по потоку?
оно то конечно все можно реализовать, вопрос во времени и целесообразности. пул вообще может довольно хитрой штукой быть, особенно для новичков в проекте, вот и получим грабли опять же.
← →
kotyara12 (2010-05-13 00:29) [53]
> не лучше ли держать пулы потоков и не тормошить систему
> постоянно их созданием уничтожением?
не думаю. по времени потоки будут создаваться через большие промежутки времени. да и выполнение в среднем будет занимать несколько часов.
к тому же пул нужно еще разобраться как реализовать - я попробовал понять как работат пул у TcpServer - мало чего понял с наскоку.
← →
DVM © (2010-05-13 00:30) [54]
> kotyara12 (13.05.10 00:25) [51]
Ты главное не теряй контроль над списком, а как удалять из списка дело десятое. Главное, чтобы в списке не оказалось дохлых ссылок и случайно не произошло обращения по дохлой ссылке.
← →
kotyara12 (2010-05-13 00:33) [55]ну да ладно, завтра продолжим "тренироваться".. еще раз всем спасибо...
зы: все равно дома sql базы нет - пробовать не на чем, а тестовый пример лепить лень.
← →
Игорь Шевченко © (2010-05-13 00:44) [56]DVM © (13.05.10 00:19) [45]
> Пока программа работает и закрываться не собирается. Но
> вот она собралась закругляться. И что у нас там летает контролировать
> сложно. Хорошо если оно там умрет своей смертью вовремя
> без последствий.
Как ты понимаешь, при завершении первичного потока процесса, автоматически завершаются все дополнительные потоки в этом процессе.
← →
sniknik © (2010-05-13 02:15) [57]блин, во у вас тут пляски с бубном...
если бы хотел уничтожить кучу потоков, с обязательным "своим" контролем, то сделал бы такfor i := 0 to Count - 1 do
Item[i].Terminate;
while ThreadCount > 0 do
Sleep(10);
for i := 0 to Count - 1 do
Item[i].Free
ну и, понятно в начале execute ThreadCount+1 в конце ThreadCount-1. и все.
мало того мороки меньше так еще и сработать в сумме должно быстрее, чем персональное ожидание завершения каждого потока (одному больше на это времени нужно другому меньше, так не "времена" не будут складываться, а будет примерно равно одному - максимальному).
← →
sniknik © (2010-05-13 02:18) [58]кстати пример потоков в дельфе (ну тот который пример сортировок) именно так и делает, насколько помню.
← →
Германн © (2010-05-13 02:30) [59]
> sniknik © (13.05.10 02:15) [57]
>
> блин, во у вас тут пляски с бубном...
>
Тут, имхо, пляшут не только Фома с Ерёмой. Тут скорее хоровод группы, каждый из которой, пляшет свой танец.
Но у всех них есть общее. Они пляшут под музыку Дельфи.
Некоторые ещё умудряются плясать под две музыки сразу. Но жалуются на сложности такой пляски.
:)
← →
Leonid Troyanovsky © (2010-05-13 07:33) [60]
> antonn © (12.05.10 23:18) [11]
> там Synchronize() случаем не нужен?
The OnTerminate event handler is called in the context of the main VCL thread
--
Regards, LVT.
← →
Leonid Troyanovsky © (2010-05-13 07:42) [61]
> Eraser © (12.05.10 23:23) [13]
> кстати, всегда интересовал такой вопрос - где правильно
> уничтожать дескриптор созданного через Begin/CreateThread
> потока? )
Тогда, когда хендл стал более не нужен.
Можно хоть сразу после BeginThread.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2010-05-13 07:57) [62]
> Игорь Шевченко © (13.05.10 00:44) [56]
> Как ты понимаешь, при завершении первичного потока процесса,
Это не всегда так. Попробуй пустить вторичный поток,
а первичному сделать ExitThread.
У Рихтера, да и в мсдн, есть условия завершения процесса (лень искать).
Одно из них: завершение при завершении последнего потока, ЕМНИП.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2010-05-13 07:59) [63]
> Rouse_ © (12.05.10 23:31) [20]
> Имеется ввиду через апи TerminateThread()
Чего мелочиться: TerminateProcess.
--
Regards, LVT.
← →
Leonid Troyanovsky © (2010-05-13 08:01) [64]
> Loginov Dmitry © (12.05.10 23:35) [27]
> Лобовой метод обхода
Военная мудрость? :)
--
Regards, LVT.
← →
Leonid Troyanovsky © (2010-05-13 08:07) [65]
> kotyara12 (13.05.10 00:29) [53]
> к тому же пул нужно еще разобраться как реализовать
http://rsdn.ru/?article/baseserv/threadpool.xml
И еще статью by Alex Fedotov
http://rsdn.ru/?summary/2393.xml
--
Regards, LVT.
← →
Rouse_ © (2010-05-13 10:25) [66]
> Loginov Dmitry © (12.05.10 23:45) [34]
> С того, что поток в этот момент занят записью какого-нибудь
> файла на жесткий диск.
И чего? Ты что не знаешь какой у тебя поток что делает и какой из них можно спокойно терминировать, а какой гарантированно висит в дедлоке? Ну-ну.
Если ПО чего-то пишет там на диск причем так, что при выключении компа оно не вырубается и мешает нормальной перезагрузке машины (ну пишет-же, чего его тревожат), то мне абсолютно пофиг на мнение разработчика данного ПО о корректности применения терминирования нити через АПИ ибо он моментально переносится в разряд криворуких и само ПО сносится с машины как класс. Помниться устанавливал я на свои машину парочку таких экземпляров - все в итоге оказались в корзине.
> DVM © (13.05.10 00:07) [39]
> 1) Мы всегда знаем, сколько у нас живых экземляров объекта
> TThread
> 2) Мы всегда можем быть уверены в том что в конкретный момент
> конкретный экземпляр жив.
> 3) Мы можем корректно закрыть все ресурсы потоков и сами
> потоки и затем уничтожить объекты TThread просто вызовом
> Terminate и WaitFor.
Чушь. Даже при включенном FreeOnTerminate мы спокойно выполняем первый и второй пункты. А третий пункт вообще ни о чем. Вот тебе пример - нить делает NtQueryObject на синхронном пайпе - я посмотрю как ты корректно завершишь такую нить.
> Лучше бы кто нибудь мне привел реальную пользу от FreeOnTerminate
А реальную пользу я тебе написал еще в [10], но ты по всей видимости пропустил этот момент.
← →
Игорь Шевченко © (2010-05-13 10:57) [67]Leonid Troyanovsky © (13.05.10 07:57) [62]
> Это не всегда так. Попробуй пустить вторичный поток,
> а первичному сделать ExitThread.
В этом случае процесс не завершается. Но тут такой момент - при завершении первичного потока вызывается не ExitThread, а ExitProcess
← →
Leonid Troyanovsky © (2010-05-13 11:38) [68]
> Игорь Шевченко © (13.05.10 10:57) [67]
> - при завершении первичного потока вызывается не ExitThread,
> а ExitProcess
Если оную не вызвал вторичный поток ;)
--
Regards, LVT.
← →
Eraser © (2010-05-13 13:57) [69]> [61] Leonid Troyanovsky © (13.05.10 07:42)
интересное замечание. когда-то давно были с этим грабли, по всей видимости из-за кривизны рук, но в мозгу отложился, как оказалось, ошибочный вывод, что нужно дожидаться окончания выполнения потока перед закрытием дескриптора. возможно теперь BeginThread будет использоваться чаще ;-)
← →
DVM © (2010-05-13 15:41) [70]
> Rouse_ © (13.05.10 10:25) [66]
> Даже при включенном FreeOnTerminate мы спокойно выполняем
> первый и второй пункты.
Выполнять то выполняем, но не кажется ли что при этом теряется все преимущество FreeOnTerminate := True - запустил и забыл?
← →
DVM © (2010-05-13 15:44) [71]
> Rouse_ © (13.05.10 10:25) [66]
> А третий пункт вообще ни о чем.
Третий пункт как раз на случай завершения приложения - проходим по списку убиваем.
> Rouse_ © (13.05.10 10:25) [66]
> Вот тебе пример - нить делает NtQueryObject на синхронном
> пайпе - я посмотрю как ты корректно завершишь такую нить.
>
Так эта...может в архитектуре надо что-то подправить, чем разбрасываться TerminateThread?
← →
RWolf © (2010-05-13 15:51) [72]> Rouse_ © (13.05.10 10:25) [66]
> Даже при включенном FreeOnTerminate мы спокойно выполняем
> первый и второй пункты.
каким образом, кстати?
экземпляры класса TMySuddenlyTerminatingThread могут стать недоступны в любой момент, значит, как-то по-другому; а как?
← →
DVM © (2010-05-13 15:53) [73]
> Вот тебе пример - нить делает NtQueryObject на синхронном
> > пайпе - я посмотрю как ты корректно завершишь такую нить.
Я сталкивался с аналогичной ситуацией, только были не пайпы, а сокеты в блокирующем режиме. Поток висел на connect() по 20 секунд и не было никакой возможности прервать поток.
Тогда же я на этом форуме высказал предположение о том, а хорошо ли будет использовать TerminateThread для быстрого выхода из приложения и прибивания таких потоков. Моментально был обруган уже не помню кем.
В результате был "изобретен" неблокирующий connect() для блокирующих сокетов.
Можно и в тупом цикле зависнуть - это не оправдание.
← →
RWolf © (2010-05-13 15:53) [74]и ещё интересен момент — кем и как будут завершаться эти созданные и забытые потоки при закрытии приложения?
← →
DVM © (2010-05-13 15:54) [75]
> RWolf © (13.05.10 15:51) [72]
> значит, как-то по-другому; а как?
изобретаем синхронизированные велосипеды, о чем я и говорил. Смысл и преимущества все теряются.
← →
Rouse_ © (2010-05-13 15:59) [76]
> экземпляры класса TMySuddenlyTerminatingThread могут стать
> недоступны в любой момент, значит, как-то по-другому; а
> как?
Перекрывая соответствующий обработчик мы избежим ситуации что они станут недоступны в любой момент :)
> DVM © (13.05.10 15:44) [71]
> Третий пункт как раз на случай завершения приложения - проходим
> по списку убиваем.
Ну не убьеш ты в сервисе, зависнешь на попытке синхронизации с основным потоком который стоит в суспенде :)
> DVM © (13.05.10 15:41) [70]
> Выполнять то выполняем, но не кажется ли что при этом теряется
> все преимущество FreeOnTerminate := True - запустил и забыл?
Вот именно - это единственное преимущество данного класса - именно запустил и забыл, все остальное гораздо качественнее и прозрачнее делается через апи, поэтому я использую класс TThread именно только в таких случаях, когда мне не нужно контролировать время его никчемной жыздни :)
← →
DVM © (2010-05-13 16:03) [77]
> Rouse_ © (13.05.10 15:59) [76]
> Ну не убьеш ты в сервисе, зависнешь на попытке синхронизации
> с основным потоком который стоит в суспенде :)
Хм. Я может чего то недопонимаю, но вот именно так я делал как то и ничего не висло.
← →
Rouse_ © (2010-05-13 16:04) [78]
> DVM © (13.05.10 15:44) [71]
> Так эта...может в архитектуре надо что-то подправить, чем
> разбрасываться TerminateThread?
Не вопрос - я с радостью выслушаю предложение по доработке вот этого примера с пересмотром архитектуры :)
http://rouse.drkb.ru/winapi.php#enumopenfiles
← →
Rouse_ © (2010-05-13 16:06) [79]
> DVM © (13.05.10 16:03) [77]
> Хм. Я может чего то недопонимаю, но вот именно так я делал
> как то и ничего не висло.
Сервис конечно-же апишный ибо я про него говрю?
т.е. без использования всякого ненужно мусора в виде VCL-ного сервиса? :)
← →
RWolf © (2010-05-13 16:09) [80]> Rouse_ © (13.05.10 15:59) [76]
> не убьеш ты в сервисе, зависнешь на попытке синхронизации
> с основным потоком который стоит в суспенде :)thd.Terminate;
thd.Resume;
//тут поток просыпается, видит, что его завершают, и выходит из Execute
thd.WaitFor;
> остальное гораздо качественнее и прозрачнее делается через
> апи
то есть через TerminateThread?
Выдержка из MSDN:
TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:
* If the target thread owns a critical section, the critical section will not be released.
* If the target thread is allocating memory from the heap, the heap lock will not be released.
* If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread’s process could be inconsistent.
* If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL
← →
DVM © (2010-05-13 16:13) [81]
> Rouse_ © (13.05.10 16:04) [78]
> http://rouse.drkb.ru/winapi.php#enumopenfiles
Будет время посмотрю :)
> Сервис конечно-же апишный ибо я про него говрю?
Я про VCL вообще то говорил.
← →
Rouse_ © (2010-05-13 16:14) [82]
> RWolf © (13.05.10 16:09) [80]
> thd.Terminate;
> thd.Resume;
> //тут поток просыпается, видит, что его завершают, и выходит
> из Execute
> thd.WaitFor;
И после этого входит в дедлок на функции thd.WaitFor.
А по поводу MSDN - это все конечно хорошо, и то что ты читаешь сию справку - выше всяких похвал, но понимаешь в чем дело, есть множество ситуаций (пару которых я привел) в которых не обойтись никак без терминирования, о чем кстати писал в свое время Руссинович описывая решение проблемы с NtQueryObject
← →
Rouse_ © (2010-05-13 16:15) [83]
> DVM © (13.05.10 16:13) [81]
> Я про VCL вообще то говорил.
VCL-ный не писал, там как раз должно быть нормально ибо вся эта ахинея с синхронизацией в отчасти как раз с огладкой на VCL-ный сервис и писалась.
А сделали бы по нормальному - синхронизация не с рутом, а с породившей нитью - вот бы сразу все шеколадно стало.
← →
RWolf © (2010-05-13 16:18) [84]
> И после этого входит в дедлок на функции thd.WaitFor.
доступ к какому ресурсу вызывает этот дедлок?
имхо, всё прозрачно — поток осознал необходимость завершиться и вышел, при этом основной поток, ожидающий его хэндл в методе thd.WaitFor, получил управление.
← →
Rouse_ © (2010-05-13 16:19) [85]
> RWolf © (13.05.10 16:18) [84]
>
>
> > И после этого входит в дедлок на функции thd.WaitFor.
>
> доступ к какому ресурсу вызывает этот дедлок?
Пфф, ну я же уже раза три писал: при синхронизации с главной нитью АПИ сервиса - которая служит для общения с SCM и все время висит в суспенде.
← →
Rouse_ © (2010-05-13 16:21) [86]Т.е. главная нить - она на самом деле не главная. Для каждого сервиса в рамках процесса создается своя нить, причем если в рамках процесса крутиться два и более сервисов (SHARE флаг) то у каждого из них своя нить, а главная всегда висит.
← →
Leonid Troyanovsky © (2010-05-13 16:25) [87]
> RWolf © (13.05.10 16:18) [84]
> > И после этого входит в дедлок на функции thd.WaitFor.
> доступ к какому ресурсу вызывает этот дедлок?
Ну, тут раньше говорили про OnTerminate, в котором поток
удалял ссылку на себя из списка.
Николай, правда, показал как в этом случае надо поступить,
т.е., Terminate по списку и ждать пока список опустеет.
--
Regards, LVT.
← →
RWolf © (2010-05-13 16:36) [88]
> при синхронизации с главной нитью АПИ сервиса - которая служит для общения с SCM и все время висит в суспенде.
пусть висит — при завершении сервиса проснётся и вызовет событие TService.OnStop, где мы и завершим все свои потоки; или нет?
← →
Игорь Шевченко © (2010-05-13 17:02) [89]Значит, борландовских Demos недостаточно. Печально.
← →
Rouse_ © (2010-05-13 17:03) [90]
> пусть висит — при завершении сервиса проснётся
А когда наступит завершение, если все три нити висят? :)
← →
Rouse_ © (2010-05-13 17:04) [91]
> и вызовет событие TService.OnStop, где мы и завершим все
> свои потоки; или нет?
Да и какой TService - ты не внимательно читаешь - я же особо упоминал про не VCL сервис :)
← →
RWolf © (2010-05-13 17:07) [92]
> А когда наступит завершение, если все три нити висят? :)
Если все висят, то такое приложение завершить можно только через диспетчер задач. Какая-то выделенная нить должна бодрствовать и ждать сигналов.
← →
Rouse_ © (2010-05-13 17:13) [93]
> RWolf © (13.05.10 17:07) [92]
> Если все висят, то такое приложение завершить можно только
> через диспетчер задач. Какая-то выделенная нить должна бодрствовать
> и ждать сигналов.
Это и есть главная нить службы - но она не бодрствует а находится в суспенде. Мехянику работы сервисов можешь почерпнуть вот из этого талмуда :)
http://rouse.drkb.ru/books.php#rihter1
← →
RWolf © (2010-05-13 17:20) [94][93]
спасибо, прочитаю.
Страницы: 1 2 3 вся ветка
Форум: "Начинающим";
Текущий архив: 2010.08.27;
Скачать: [xml.tar.bz2];
Память: 0.73 MB
Время: 0.077 c