Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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.071 c
15-1267047005
Юрий
2010-02-25 00:30
2010.08.27
С днем рождения ! 25 февраля 2010 четверг


15-1265185685
Сергей М.
2010-02-03 11:28
2010.08.27
Про VisualFoxPro и COM-серверы


15-1273558498
@!!ex
2010-05-11 10:14
2010.08.27
Дешевое копирование выходит за рамки ПО.


6-1217938741
leonidus
2008-08-05 16:19
2010.08.27
Извлечение текста из WebBrowser`а


4-1234856626
Encore
2009-02-17 10:43
2010.08.27
Handle процесса





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