Форум: "Потрепаться";
Текущий архив: 2004.05.23;
Скачать: [xml.tar.bz2];
ВнизСоветы Рихтера не пользоватся 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;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.033 c