Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Потрепаться";
Текущий архив: 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
1-1083772275
RiKo
2004-05-05 19:51
2004.05.23
сброс параметров


1-1084173767
Master Paleva
2004-05-10 11:22
2004.05.23
Как освободить память?


14-1083457127
VID
2004-05-02 04:18
2004.05.23
Спим ?


3-1083316153
max1000
2004-04-30 13:09
2004.05.23
Interbase и права пользователям


1-1083916212
V-Isa
2004-05-07 11:50
2004.05.23
Проблеиа с сохранением JPEG





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