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

Вниз

Советы Рихтера не пользоватся ExitThread.   Найти похожие ветки 

 
Тимохов ©   (2004-04-30 16:07) [0]

Уважаемые, Мастера.

При прочтении Рихтера изд.4 наткнулся на совет - самый лучший способ завершить поток это окончить потоковую функцию. Другие метода - ExitThread и TermianteThread по мнению Рихтера не являются приемлемыми (т.е. не рекоммендованными). При этом я плохо понял, чем он это аргументирует. Насколько я понял, главным аргументом является то, что деструкторы сишных объектов вызваны не будут.

При этом я заметил, что TThread в дельфи выход из поточной функции делает через ExitThread (модуль classes функция ThreadProc).

Вопрос.
Как вы относитесь, к тому, что в дельфи остановка потока реализовна не в соответствии с рекоммендациями Рихтера? Кто здесь не прав: Рихтер или Борланд? Или оба правы, т.к. Рихтер имел в виду, что ExitThread не надо использовать в ходе работы потоковой функции не вызвав деструкторы объектов, а Борланд сознательно вызывает эту функцию в конце потоковой функции, явно понимая, что это не может привести к ошибкам, т.к. по идее программист уже должен был сам освободить все ресурсы, и если он (Борланд) вызовет ExitThread, то это уж никак никому не навредит. В общем путанный немного вопрос, но главное следующее - ваше к этому отношение?


 
Digitman ©   (2004-04-30 16:16) [1]


> в дельфи остановка потока реализовна не в соответствии с
> рекоммендациями Рихтера


чавой-то ?!!

ты, мил мой,  понахреновертил в теле Execute(), поназанимал ресурсов посамое нехочу - и хочешь чтобы Борланд за тебя их освобождал ?!

Нетушки ! Борланду больше делать нечего как пасти тебя) ... Борланд справедливо полагает, что  ты САМ ответственен за распределение ресурсов ! С учетом твоих знаний скрытых возможностей его, Борланда, компилятора ... А его, Борланда, задача - инкапсулировать механизм управления потоками в класс TThread, чтобы ты не парился и не изобретал всякоразные пестрые классы/сторуктуры и не вляпывался день ото дня в проблему упрощеного (с т.з. ООП в дан.случае) и надежного доступа к ОС-объектам дан.класса


 
Calm ©   (2004-04-30 16:22) [2]


> ты, мил мой,  понахреновертил в теле Execute(), поназанимал
> ресурсов посамое нехочу - и хочешь чтобы Борланд за тебя
> их освобождал ?!

Непонятно, какие притенции вы предъявляете Тимохову.
По-моему, он о своих программах, подходах и взглядах вообще не высказывался.


 
Тимохов ©   (2004-04-30 16:26) [3]


> Digitman ©   (30.04.04 16:16) [1]


> чавой-то ?!!

Ну я примерно это и сказал - что борланд вызывает ExitThread, т.к. полагает, что я сам дурак если не поосвобождал ресурсы.

Т.е. я так понимаю, что ничего криминального в ExitThread нет.

Правильно я понимаю, что ExitThread можно было бы и не вызывать, но тогда не понятно куда девать код возврата?

А что вы скажете про TerminateThread - пользуетесь им?
Или все же пытаетесь всеми доступными средствами закончить execute? Поясню почему вопрос. Мы все-таки остановились на синхронных сокетах (для асинхроных знаний не хватает). Поэтому recv будет "висеть". Насколько я понимаю его можно срубить из другого потока через CloseSocket, обработать ошибку и выйти из execute. Но ведь можно просто - TerminateThread. Последнее, насколько я понимаю хуже. Так?


 
Матлабист   (2004-04-30 16:32) [4]

Вопрос в том, чтобы понимать, что при сем происходит. C++ ближе оперирует с функциями API, нежели Delphi. Поэтому такой код

void ThreadProc(void* Arg)
{
 TSomeObj Test();
 ExitThread(0);
 // ~Test();
}


приведет к тому, что объект TSomeObj не будет уничтожен, потому как C++ по умолчанию вставит код вызова деструктора уже после ExitThread (когда поток умер). (Если быть более точным, то в секции finally, до которой не доживет)

Но такой вариант

void TestProc()
{
 TSomeObj Test();
}

void ThreadProc(void* Arg)
{
 TestProc();
 ExitThread(0);
 // Нет неявного кода}


имеет все права на жизнь, так как объект Test создастся и успешно уничтожится, а функция ThreadProc не имеет неявного кода перед }

Рассмотрим реализацию Delphi (5):

function ThreadProc(Thread: TThread): Integer;
var
 FreeThread: Boolean;
begin
 try
   Thread.Execute;
 finally
   FreeThread := Thread.FFreeOnTerminate;
   Result := Thread.FReturnValue;
   Thread.FFinished := True;
   Thread.DoTerminate;
   if FreeThread then Thread.Free;
   EndThread(Result); // Сводится в простому ExitThread(Result)  end;
end;


Все в порядке --- функция не содержит локальных переменных с автоматическим менеджментом памяти, поэтому после EndThread нет никаких вызовов. Естественно, что то, что ты наплодил в коде TYourThread.Execute должно быть уничтожено после выхода из этого метода. Тут за тебя Delphi не в ответе.


 
Тимохов ©   (2004-04-30 16:36) [5]


> Матлабист   (30.04.04 16:32) [4]

Спасибо.
Я не очень знаком с ООП в си (просто совсем не знаю, знаю только, что есть :)).
По сему и возник вопрос, почему Рихтер так на это упирает.


 
Матлабист   (2004-04-30 16:38) [6]

TerminateThread пользоваться можно. Утечек памяти не будет, если код потока, например, вообще не оперирует динамической памятью ;) Например, функцию

function MyThreadFunc(Arg: Pointer);
var
 I: Int64;
begin
 I := 0;
 while I <> 0 do Inc(I);
end;


легко можно прервать вызовом TerminateThread

А вот эту

function MyThreadFunc(Arg: Pointer);
var
 I: Int64;
 St: string;
begin
 I := 0;
 while I <> 0 do
 begin

   St := IntToStr(I);
   Inc(I);
 end;
end;


прерывать рисковано --- значение, на которое указывает  St, просто останется в памяти.


 
Digitman ©   (2004-04-30 16:39) [7]


> Calm ©   (30.04.04 16:22) [2]


это - без претензий к компетенции ув.коллеги Тимохова) ... не адресно. разумеется ... в контексте, т.с., "непривязанногго базара"))

шутка юмора)... миль пардон, коли не понята)


> Тимохов ©   (30.04.04 16:07)  


procedure ГлюкаваяФорма.ГлюкавыйТрэдExecute;
begin
 SomeResource := GetSomeSystemResource(..);
 if SomeCondition then
   ExitThread(..); // здесь мемлик гарантирован
 Free(SomeResource);
end;


 
Тимохов ©   (2004-04-30 16:42) [8]


> Digitman ©   (30.04.04 16:39) [7]

Т.е. если мне надо прервать синхронное ожидание recv, нужно делать это из другого потока средствами сокетов, обработать ошибку recv и штатно выйти из execute?


 
Тимохов ©   (2004-04-30 16:44) [9]


> Матлабист   (30.04.04 16:38) [6]

Про второй пример (с утечной).
Насколько я понимаю утечка дейсвтиетльно будет, т.к. для строки St память будет резервировать не в стеке потока, а в куче процесса. Стек то освободится, а кучу никто освобождать до конца процесса не будет...
Наверное так?


 
Матлабист   (2004-04-30 16:46) [10]

Аналогичный пример на Delphi:

function MyThreadFunc(Arg: Pointer);
var
 St: string;
begin
 St := "Test string";
 MessageBox(PChar(St), ...)
 ExitThread (0);
end;


приведет к утечке памяти, так как на более низком рассмотрении этот код есть

function MyThreadFunc(Arg: Pointer);
var
 St: string;
begin
 InitializeString(St);
 try
   St := "Test string";
   MessageBox(PChar(St), ...)
   ExitThread (0);
 finally
   FinalizeString(St); // Увы, не выполнится
 end;
end;


и код для FinalizeString выполнен не будет. Просто Рихтер предлагает либо самому следить также и за неявным кодом, сгенерированым компилятором, либо просто не пользоваться ExitThread и TerminateThread.


 
Матлабист   (2004-04-30 16:48) [11]

Да, так


 
Digitman ©   (2004-04-30 16:50) [12]


> Тимохов ©   (30.04.04 16:42) [8]


вызову recv() в данном потоке, согласись, предшествовала куча программных действий ... начиная с WSAStartup() .. которому в ДАННОМ потоке, пока он жив, должна соответствовать WSACleanUp()() ... при завершении поточной ф-ции по ExitThread() ни о каких WSACleanUp() говорить не приходится - вот тебе и минимально обозримый повод для мемлика !  Не говоря уже о "разорванной" паре Socket() + CloseSocket() .. ибо гнездо как объект ОС после создания ассоциировано со структурой в ВАП процесса .. а структура - это занятая вирт.память


 
Тимохов ©   (2004-04-30 17:24) [13]


> Digitman ©   (30.04.04 16:50) [12]

Правильно ли я понимаю, что вы подразумеваете, что вызову recv в данном потоке обязательно должен предшествовать вызов WSAStartUp в том же потоке?


 
Игорь Шевченко ©   (2004-04-30 18:40) [14]


> Как вы относитесь, к тому, что в дельфи остановка потока
> реализовна не в соответствии с рекоммендациями Рихтера?
> Кто здесь не прав: Рихтер или Борланд? Или оба правы


Рихтер пишет, что не надо использовать ExitThread в программах, написанных на С/С++. Поскольку Delphi не относится ни к тому, ни к другому языку, можно считать, что правы оба. Библиотеки времени выполнения для этих языков совершенно разные, так что ряда проблем, описанных Рихтером в Delphi просто не будет. Кроме того, в Delphi объекта динамические, в отличие от С++, где реализована возможность статических объектов, для которых конструкторы и деструкторы вызываются автоматически.
Как Delphi использует в RTL локальную память потока, о которой тоже говорит Рихтер, я в деталях не помню, но полагаю, что в Borland работают далеко не дураки, и Рихтера они тоже читали.



Страницы: 1 вся ветка

Текущий архив: 2004.05.23;
Скачать: CL | DM;

Наверх




Память: 0.52 MB
Время: 0.025 c
11-1071066173
.::D.e.M.o.N.i.X::.
2003-12-10 17:22
2004.05.23
Что не так в коде???


1-1084350344
glGLU
2004-05-12 12:25
2004.05.23
Menu


7-1082181103
dvl92
2004-04-17 09:51
2004.05.23
Как импортировать ссылки которые хранятся в "ИЗБРАННОМ" IE?


6-1080736606
Игорь
2004-03-31 16:36
2004.05.23
WebBrowser: поиск текста


6-1080805579
Max_
2004-04-01 11:46
2004.05.23
событие onNewWindow компонента TwebBrowser