Форум: "Прочее";
Текущий архив: 2008.05.11;
Скачать: [xml.tar.bz2];
Внизоцените пожалуйста код Найти похожие ветки
← →
@!!ex © (2008-03-25 21:19) [0]Сейчас встала задача распаралеливания вычислений. Она уже несколько раз вставала, но раньше удавалось ее обходить. Теперь вопрос встал ребром...
Написал вот модуль, для работы с потоками. Но так как в теме еще понимаю мало, хочеться узнать, насколько правильно я его написал.unit uThread;
interface
uses
Windows;
type
TCriticalSection = class
private
FSection:_RTL_CRITICAL_SECTION;
public
Constructor Create;
Destructor Destroy; override;
Procedure Enter;
Procedure Leave;
end;
TSemaphore = class
private
FSemaphore:Cardinal;
public
Constructor Create;
Destructor Destroy; override;
Procedure Enter;
Function TryEnter:boolean;
Procedure Leave(Count:integer = 1);
end;
TThread = class
protected
FStateTHRead:integer;
FIsTerminated:boolean;
FThread:integer;
FLock:TCriticalSection;
Function StateThread:integer;
Function StartThread(IsSuspend:boolean = true):boolean;
public
Constructor Create(IsSuspend:boolean = true);
Destructor Destroy; override;
Procedure Execute; virtual; abstract;
Procedure Wait;
Procedure Suspend;
Procedure Resume;
Procedure Terminate;
Function Terminated:boolean;
property Lock:TCriticalSection read FLock;
end;
implementation
{ TCriticalSection }
constructor TCriticalSection.Create;
begin
InitializeCriticalSection(FSection);
end;
destructor TCriticalSection.Destroy;
begin
DeleteCriticalSection(FSection);
inherited;
end;
procedure TCriticalSection.Enter;
begin
EnterCriticalSection(FSection);
end;
procedure TCriticalSection.Leave;
begin
LeaveCriticalSection(FSection);
end;
{ TSemaphore }
constructor TSemaphore.Create;
begin
FSemaphore := CreateSemaphore(nil, 0, 100000000, nil);
end;
destructor TSemaphore.Destroy;
begin
CloseHandle(FSemaphore);
inherited;
end;
procedure TSemaphore.Enter;
begin
WaitForSingleObject(FSemaphore, INFINITE);
end;
procedure TSemaphore.Leave(Count: integer);
begin
ReleaseSemaphore(FSemaphore, Count, nil);
end;
function TSemaphore.TryEnter: boolean;
begin
Result:=not WaitForSingleObject(FSemaphore, 0)=WAIT_TIMEOUT;
end;
const
ST_NONE = 0;
ST_SUSPEND = 1;
ST_RESUME = 2;
ST_STOP = 3;
function ObjectNewTHRead(lpThreadParameter: TThread): Integer; stdcall;
begin
lpThreadParameter.Execute();
lpThreadParameter.Lock.Enter();
lpThreadParameter.FStateTHRead := ST_STOP;
lpThreadParameter.Lock.Leave();
Result:=0;
end;
{ TThread }
constructor TThread.Create(IsSuspend: boolean);
begin
FIsTerminated := false;
if IsSuspend then
FStateTHRead:=ST_SUSPEND
else
FStateTHRead:=ST_RESUME;
if not StartThRead(IsSuspend) then
FStateTHRead:=ST_NONE;
end;
destructor TThread.Destroy;
begin
Terminate();
Wait();
inherited;
end;
procedure TThread.Resume;
begin
Lock.Enter();
if FStateTHRead = ST_SUSPEND then begin
ResumeThread(FTHRead);
FStateTHRead := ST_RESUME;
end;
Lock.Leave();
end;
function TThread.StartThread(IsSuspend: boolean): boolean;
var
dwTHID:cardinal;
begin
if IsSuspend then
FThread:=CreateThread(nil,100000,@ObjectNewTHRead,self,CREATE_SUSPENDED,dwTHID)
else
FThread:=CreateThread(nil,100000,@ObjectNewTHRead,self,0,dwTHID);
Result:=FThread<>0;
end;
function TThread.StateThread: integer;
begin
Lock.Enter();
Result := FStateTHRead;
Lock.Leave();
end;
procedure TThread.Suspend;
begin
Lock.Enter();
if FStateTHRead=ST_RESUME then begin
SuspendThread(FTHRead);
FStateTHRead := ST_SUSPEND;
end;
Lock.Leave();
end;
procedure TThread.Terminate;
begin
Lock.Enter();
FIsTerminated := TRUE;
Lock.Leave();
Resume();
end;
function TThread.Terminated: boolean;
begin
Lock.Enter();
Result := FIsTerminated;
Lock.Leave();
end;
procedure TThread.Wait;
begin
if StateTHRead()<>ST_NONE then begin
WaitForSingleObject(FTHRead,INFINITE);
CloseHandle(FTHRead);
end;
FStateTHRead := ST_NONE;
end;
end.
← →
Джо © (2008-03-25 21:20) [1]Даже не глядя в код, спрошу — а зачем создавать свой TCriticalSection, если оный уже есть в VCL?
← →
Джо © (2008-03-25 21:21) [2]И остальные тоже...
← →
@!!ex © (2008-03-25 21:23) [3]> а зачем создавать свой TCriticalSection, если оный уже есть
> в VCL?
Ну во-первых я не знал что в VCL это уже есть. :)
А во-вторых - использование VCL нельзя использовать, т.к. проект планируется компилять под FPC, и возможно переписывать под C++.
← →
Informer (2008-03-25 21:31) [4]> @!!ex © (25.03.08 21:23) [3]
А почему бы сразу не писАть на С++?
← →
DVM © (2008-03-25 21:32) [5]
> procedure TThread.Terminate;
> begin
> Lock.Enter();
> FIsTerminated := TRUE;
> Lock.Leave();
> Resume();
> end;
ИМХО критические секции тут вообще лишние.
Вот предложу такой вариант:
unit Threads;
interface
uses Windows;
////////////////////////////////////////////////////////////////////////////////
// TThread
////////////////////////////////////////////////////////////////////////////////
type
TThreadMethod = procedure of object;
TThreadPriority = (tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest,
tpTimeCritical);
const
Priorities: array [TThreadPriority] of Integer =
(THREAD_PRIORITY_IDLE,
THREAD_PRIORITY_LOWEST,
THREAD_PRIORITY_BELOW_NORMAL,
THREAD_PRIORITY_NORMAL,
THREAD_PRIORITY_ABOVE_NORMAL,
THREAD_PRIORITY_HIGHEST,
THREAD_PRIORITY_TIME_CRITICAL);
type
TThread = class
private
FHandle: THandle;
FThreadID: THandle;
FTerminated: Boolean;
FSuspended: Boolean;
FFreeOnTerminate: Boolean;
FFinished: Boolean;
FReturnValue: DWORD;
function GetPriority: TThreadPriority;
procedure SetPriority(Value: TThreadPriority);
procedure SetSuspended(Value: Boolean);
protected
procedure Execute; virtual; abstract;
property ReturnValue: DWORD read FReturnValue write FReturnValue;
property Terminated: Boolean read FTerminated;
public
constructor Create(CreateSuspended: Boolean);
destructor Destroy; override;
procedure Resume;
procedure Suspend;
procedure Terminate;
procedure WaitFor;
property FreeOnTerminate: Boolean read FFreeOnTerminate write FFreeOnTerminate;
property Handle: THandle read FHandle;
property Priority: TThreadPriority read GetPriority write SetPriority;
property Suspended: Boolean read FSuspended write SetSuspended;
property ThreadID: THandle read FThreadID;
end;
implementation
////////////////////////////////////////////////////////////////////////////////
// TThread
////////////////////////////////////////////////////////////////////////////////
function ThreadProc(Thread: TThread): DWORD;
var
FreeThread: Boolean;
begin
Thread.Execute;
FreeThread := Thread.FFreeOnTerminate;
Result := Thread.FReturnValue;
Thread.FFinished := True;
if FreeThread then Thread.Free;
EndThread(Result);
end;
//------------------------------------------------------------------------------
constructor TThread.Create(CreateSuspended: Boolean);
var
Flags: DWORD;
begin
inherited Create;
FSuspended := CreateSuspended;
Flags := 0;
if CreateSuspended then Flags := CREATE_SUSPENDED;
FHandle := BeginThread(nil, 0, @ThreadProc, Pointer(Self), Flags, FThreadID);
end;
//------------------------------------------------------------------------------
destructor TThread.Destroy;
begin
if FHandle <> 0 then CloseHandle(FHandle);
inherited Destroy;
end;
//------------------------------------------------------------------------------
function TThread.GetPriority: TThreadPriority;
var
P: Integer;
I: TThreadPriority;
begin
P := GetThreadPriority(FHandle);
Result := tpNormal;
for I := Low(TThreadPriority) to High(TThreadPriority) do
if Priorities[I] = P then Result := I;
end;
//------------------------------------------------------------------------------
procedure TThread.SetPriority(Value: TThreadPriority);
begin
SetThreadPriority(FHandle, Priorities[Value]);
end;
//------------------------------------------------------------------------------
procedure TThread.SetSuspended(Value: Boolean);
begin
if Value <> FSuspended then
if Value then
Suspend
else
Resume;
end;
//------------------------------------------------------------------------------
procedure TThread.Suspend;
begin
FSuspended := True;
SuspendThread(FHandle);
end;
//------------------------------------------------------------------------------
procedure TThread.Resume;
begin
if ResumeThread(FHandle) = 1 then FSuspended := False;
end;
//------------------------------------------------------------------------------
procedure TThread.Terminate;
begin
FTerminated := True;
end;
//------------------------------------------------------------------------------
procedure TThread.WaitFor;
begin
WaitForSingleObject(FHandle, INFINITE);
end;
//------------------------------------------------------------------------------
end.
← →
ага (2008-03-25 21:33) [6]
> constructor TThread.Create(IsSuspend: boolean);
> begin
> FIsTerminated := false;
> procedure TThread.Terminate;
> begin
> Lock.Enter();
> FIsTerminated := TRUE;
Нафига??
← →
ага (2008-03-25 21:36) [7]
> DVM © (25.03.08 21:32) [5]
> procedure TThread.Terminate;
> begin
> FTerminated := True;
> end;
Аналогично - нафига?
← →
@!!ex © (2008-03-25 21:37) [8]> [6] ага (25.03.08 21:33)
В Execute следишь за состоянием FIsTerminated, если true - выходим.
> ИМХО критические секции тут вообще лишние.
А вдруг присвоение не атомарное? :)
← →
DVM © (2008-03-25 21:40) [9]
> ага (25.03.08 21:36) [7]
> Аналогично - нафига?
Не понимаю вопроса. Что смущает? Выставляется флаг завершения, процедура, которая будет крутиться в методе Execute должна проверять состояние флага.
> А вдруг присвоение не атомарное? :)
Даже если не атомарное ничего не случится.
← →
@!!ex © (2008-03-25 21:40) [10]> [4] Informer (25.03.08 21:31)
А смысл?
Я на дельфи быстрее пишу и качесвтенней.
← →
DVM © (2008-03-25 21:43) [11]
> Я на дельфи быстрее пишу и качесвтенней.
На Delphi вообще все пишут качественнее. Я вот тут месяц с лишним писал на си (без плюсов) для некоего девайса (даже на неком подмножестве турбо си). Отсутствие типа строка просто убивало. Мало того, что неудобно, так еще и очень очень внимательным надо быть, чтобы не дай бог не вылезти за границы массива или \0 не забыть где.
← →
ага (2008-03-25 21:46) [12]
> @!!ex © (25.03.08 21:37) [8]
> DVM © (25.03.08 21:40) [9]
У tthread уже есть terminated. Зачем самодеятельность?
← →
DVM © (2008-03-25 21:49) [13]
> У tthread уже есть terminated. Зачем самодеятельность?
У кого есть? Этот код рассматривается как раз как альтернатива классу TThread из Classes. К тому же terminated стандартного класса TThread это не то же самое, что terminate того же класса.
← →
ага (2008-03-25 21:54) [14]
> DVM © (25.03.08 21:49) [13]
>
>
> > У tthread уже есть terminated. Зачем самодеятельность?
>
>
> У кого есть? Этот код рассматривается как раз как альтернатива
> классу TThread из Classes. К тому же terminated стандартного
> класса TThread это не то же самое, что terminate того же
> класса.
terminated - тот же флаг. Terminate тоже выставляет значение этого флага, но никто не
мешает вручную безболезненно выставлять этот флаг аналогично [0] и [5].
И зачем вообще велосипеды изобретать?
← →
Игорь Шевченко © (2008-03-25 21:57) [15]
> Написал вот модуль, для работы с потоками. Но так как в
> теме еще понимаю мало
А TThread использовать религия не велит ?
← →
DVM © (2008-03-25 21:59) [16]
> но никто не
> мешает вручную безболезненно выставлять этот флаг аналогично
> [0] и [5].
Мешает, ибо:
property Terminated: Boolean read FTerminated;
> И зачем вообще велосипеды изобретать?
Затем, чтобы использовать FreePascal и не использовать модуль Classes например. К тому же можно создать более гибкую и более удобную реализацию обертки под поток, чем в Classes.
← →
ага (2008-03-25 22:09) [17]
> DVM © (25.03.08 21:59) [16]
>
>
> > но никто не
> > мешает вручную безболезненно выставлять этот флаг аналогично
> > [0] и [5].
>
> Мешает, ибо:
Не мешает.
И, к стати, в FCL тоже есть tthread.
← →
Mystic © (2008-03-25 22:14) [18]
> А во-вторых - использование VCL нельзя использовать, т.к.
> проект планируется компилять под FPC, и возможно переписывать
> под C++.
Насколько я знаю, под FPC есть классы, аналогичные VCL. Причем реализованные как под Win, так и под *nix. В крайнем случае можно скопировать реализацию из VCL, или взять ее за основу :)
Во-вторых, есть много различных библиотек под C++, где это все уже реализовано, да еще в кроссплатформенном виде :)
В-третьих, мало кому интересны обвертки над VCL. Вот если бы ты описал свою задачу и с помочу чего и как т ыхочешь распараллелить.. А так... Это техника...
В четвертых, Lock.Enter и Lock.Leave надо оборачивать в try..finally
В пятых, функцией CreateThread пользоваться низзя, надо использовать BeginThread. Основная причина в том, что BeginThread устанавливает переменную IsMultyThread в True. А она используется, например, в менеджере памяти (надо или не надо входить в критическую секцию). Поэтому могут быть труднонаходимые проблемы. Конечно, если код потока не испольуется строк и других объектов с автоматическим управлением памятью, то можно и CreateThread вызвать...
В шестых, константы состояния потока закрыты (implementation), а функция StateThread обкрыта (protected).
В седьмых, CloseHandle для потока лучше перенести в деструктор. Теоретически (1) поток можно ждать и после его завершения, (2) Wait могут вызвать разные потоки
Ну и далее общее пожелание:
>> DVM © (25.03.08 21:32) [5]
Очень часто поток валится из-за исключения. В этом случае он просто убивается и все. В твоем случае ты об этом так и не узнаешь. Посему правильнее было бы написать:
function ThreadProc(Thread: TThread): DWORD;
var
FreeThread: Boolean;
begin
try
Thread.Execute;
except
on E: Exceptions do
Windows.MessageBox(...); // Хотя-бы вывести отладочное сообщение
// Другая нужная обработка
end;
try
FreeThread := Thread.FFreeOnTerminate;
Result := Thread.FReturnValue;
Thread.FFinished := True;
if FreeThread then Thread.Free;
EndThread(Result);
except
on E: Exceptions do
// А сюда мы можем попасть если некто сделал Free() данному потоку в момент его работы.
// Тоже желательно провести диагностику
end;
end;
← →
DVM © (2008-03-25 22:15) [19]
> Не мешает.
Я тебе привел строчку из класса TTread модуля Classes.
property Terminated: Boolean read FTerminated;
Из нее следует, что свойство Terminated только для чтения. И создав экземпляр этого класса, ты не сможешь извне менять состояние свойства напрямую, а только через метод Terminate. Неужели непонятно?
Ясен пень, что можно написать и по другому и вооюще несколькими способами. Но так уж повелось, что некоторые объекты имеют свойства и методы меняющие эти свойства. Иногда даже если свойства не только для чтеня. Например свойство Active и Connect у оберток под сокеты.
> И, к стати, в FCL тоже есть tthread.
Ты это не мне доказывай, а автору вопроса, меня вообще и стандартный TThread устраивает.
← →
Игорь Шевченко © (2008-03-25 22:22) [20]
> и не использовать модуль Classes например
А что, использование модуля Classes considered harmful ?
← →
ага (2008-03-25 22:24) [21]
> DVM © (25.03.08 22:15) [19]
>
>
> > Не мешает.
>
> Я тебе привел строчку из класса TTread модуля Classes.
А нет у меня D. По памяти пишу. И, на сколько помню - в terminate ничего кроме
выставления terminated=true не делается. Этого достаточно.
> Ты это не мне доказывай, а автору вопроса
Я никому ничего не доказываю. Просто дискуссия.
← →
DVM © (2008-03-25 22:29) [22]
> Игорь Шевченко © (25.03.08 22:22) [20]
>
> > и не использовать модуль Classes например
>
>
> А что, использование модуля Classes considered harmful
Какой Classes может быть под FreePascal? Даже, если он там и скомпилируется, то все равно это нарушение лицензии.
← →
Игорь Шевченко © (2008-03-25 22:31) [23]DVM © (25.03.08 22:29) [22]
Я снес FreePascal вместе с lazarus, так что ничего не могу сказать на этот предмет. А что, и модуля SysUtils там нету ? :)
← →
DVM © (2008-03-25 22:34) [24]
> А что, и модуля SysUtils там нету ? :)
Я понятия не имею, не использовал FreePascal толком. Lazarus же вообще оставил впечатление жуткой недоработки. Но тем не менее они есть и, в отличие от Delphi могут компилировать под разные платформы, в том числе и под 64 bit.
← →
Mystic © (2008-03-25 22:38) [25]
>
> Какой Classes может быть под FreePascal? Даже, если он
> там и скомпилируется, то все равно это нарушение лицензии.
Свой собственный, немного расширенный, портированный под Linux.
← →
ага (2008-03-25 22:39) [26]
> DVM © (25.03.08 22:29) [22]
>
> Какой Classes может быть под FreePascal?
Поставь уже FPC и посмотри какой.
← →
DVM © (2008-03-25 22:42) [27]
> Свой собственный
Свой понятно, что там есть. Но речь, насколько я понял, изначально шла о том, чтобы одно и то же приложение могло с одинаковым успехом компилироваться и в Delphi и во FreePascal. Такое наверняка проще обеспечить, если создать свою обертку под поток, а не использовать возможно сильно отличающиеся классы из разных модулей Classes.
← →
DVM © (2008-03-25 22:44) [28]
> Поставь уже FPC и посмотри какой.
Зачем мне на него смотреть. Ты просто не понял моей фразы. Надо читать как "Какой модуль Classes из Delphi может быть во FreePascal".
← →
ага (2008-03-25 22:52) [29]
> DVM © (25.03.08 22:44) [28]
Из D? портированный... Можно сказать самодельный.
Там есть и tstream и tstrings и tstringlist и почти все, что есть в classes delphi.
Почти-это имхо, потому что я не особо интересуюсь и всех тонкостей не знаю.
← →
DiamondShark © (2008-03-25 23:53) [30]
> К тому же можно создать более гибкую и более удобную реализацию
> обертки под поток
Обёртки для таких примитивных сущностей -- это верх маразма.
А использование слова-паразита "гибкую" -- тревожный симптом повышенной толерантности к маркетоложеству.
Попытка создания "гибкости" вокруг примитивной вещи приводит к нагромождению кода, к "протекающим абстракциям" и, в конце концов, к потере той самой "гибкости", за которую боролись.
← →
DVM © (2008-03-26 00:01) [31]
> Обёртки для таких примитивных сущностей -- это верх маразма.
Значит в борланде одни маразматики.
> Попытка создания "гибкости" вокруг примитивной вещи
Насчет примитивности задачи создания обертки для потока не согласен категорически.
> Попытка создания "гибкости" вокруг примитивной вещи приводит
> к нагромождению кода
Гибкость и размер кода никак не связаны между собой.
> А использование слова-паразита "гибкую"
Первый раз слышу о таком слове "паразите".
← →
DVM © (2008-03-26 00:05) [32]
> Обёртки для таких примитивных сущностей -- это верх маразма.
У меня почему то складывается такое ощущение, что вы никогда не работали над многопоточными риложениями. Странные рассуждения какие то.
← →
Anatoly Podgoretsky © (2008-03-26 00:40) [33]> DVM (25.03.2008 22:15:19) [19]
> Из нее следует, что свойство Terminated только для чтения. И создав экземпляр этого класса, ты не сможешь извне менять состояние свойства напрямую, а только через метод Terminate.
Что бы не выстрелить себе в ногу.
← →
Anatoly Podgoretsky © (2008-03-26 00:43) [34]> DiamondShark (25.03.2008 23:53:30) [30]
Красиво излагаешь.
← →
DiamondShark © (2008-03-26 12:29) [35]
> DVM © (26.03.08 00:01) [31]
>
> > Обёртки для таких примитивных сущностей -- это верх маразма.
>
> Значит в борланде одни маразматики.
Странный вывод. Ви, таки, намекаете, что Борланд не написал ничего, кроме обёрток над простыми вещами?
> > Попытка создания "гибкости" вокруг примитивной вещи
>
> Насчет примитивности задачи создания обертки для потока
> не согласен категорически.
Будете смеяться, но я тоже. Задачу можно себе наворотить как угодно, было бы желание. Кто ж тут спорит?
Но, видите ли, я нигде не говорил о примитивности задачи создания обертки, я говорил о примитивной вещи. Поток -- вещь примитивная (говорим, конечно, не о потрохах ядра, а об уровне прикладного ПО). Есть возражения?
> Гибкость и размер кода никак не связаны между собой.
Увы, связаны. Даже у очень простой вещи может быть множество сценариев использования. Гибкая обёртка должна предусматривать их либо все, либо большинство, либо, хотя бы, значительную часть, иначе она уже не будет гибкой, или не будет обёрткой. Если обёртка не прусматривает какого-либо интересного сценария, ей будет невозможно пользоваться, потому что хорошая непротекающая обёртка тщательно скрывает детали реализации. Или обёртка вынуждена предоставлять какие-нибудь хуки-хаки, вроде выставления public-свойством Handle оборачиваемого объекта. И то и другое оборачивается мусорным кодом: либо неиспользуемым библиотечным, либо пользовательскими костылями.
А если оборачиваемая сущность достаточно проста (как в случае потока), то обёртка, в наименее патологическом случае, вырождается в пересказ низлежащего API другими словами. Но в этом случае теряется сам смысл обертки: никакая новая абстракция не вводится, ни объём, ни сложность прикладного кода не меняются (хе-хе;) если не увеличиваются). Посмотрите, чего полезного вносит использование класса TThread вместо BeginThread? Да ничего.
> Первый раз слышу о таком слове "паразите".
Да ладно! Сплошь и рядом слышатся уверения, что-де такой-то программный продукт "гибкий". Как правило, в переводе на русский это означает что продукт монстроузный, с мутной логикой и требующий обработки напильником перед сколь-нибудь продуктивным использованием.
> У меня почему то складывается такое ощущение, что вы никогда
> не работали над многопоточными риложениями. Странные рассуждения
> какие то.
У меня, почему-то, SKLадывается ощущение, что Вы, таки, решили перейти на личности, не въехав толком в рассуждения.
← →
@!!ex © (2008-03-26 12:53) [36]> Увы, связаны. Даже у очень простой вещи может быть множество
> сценариев использования. Гибкая обёртка должна предусматривать
> их либо все, либо большинство, либо, хотя бы, значительную
> часть, иначе она уже не будет гибкой, или не будет обёрткой.
> Если обёртка не прусматривает какого-либо интересного сценария,
> ей будет невозможно пользоваться, потому что хорошая непротекающая
> обёртка тщательно скрывает детали реализации. Или обёртка
> вынуждена предоставлять какие-нибудь хуки-хаки, вроде выставления
> public-свойством Handle оборачиваемого объекта. И то и другое
> оборачивается мусорным кодом: либо неиспользуемым библиотечным,
> либо пользовательскими костылями.
> А если оборачиваемая сущность достаточно проста (как в случае
> потока), то обёртка, в наименее патологическом случае, вырождается
> в пересказ низлежащего API другими словами. Но в этом случае
> теряется сам смысл обертки: никакая новая абстракция не
> вводится, ни объём, ни сложность прикладного кода не меняются
> (хе-хе;) если не увеличиваются). Посмотрите, чего полезного
> вносит использование класса TThread вместо BeginThread?
> Да ничего.
Да ун ерунду говорите.
Интерфейс нужен хотя бы для того, чтобы избавиться от процедурного программирования.
ООП нагляднее однако. Поток легче контролировать. Нигде не надо хранить идентефикатор потока и т.д.
← →
Игорь Шевченко © (2008-03-26 13:19) [37]
> Да ун ерунду говорите.
> Интерфейс нужен хотя бы для того, чтобы избавиться от процедурного
> программирования.
> ООП нагляднее однако. Поток легче контролировать. Нигде
> не надо хранить идентефикатор потока и т.д.
Это вы ерунду говорите. Уж извините, но это так.
← →
Mystic © (2008-03-26 13:20) [38]> Но речь, насколько я понял, изначально шла о том, чтобы
> одно и то же приложение могло с одинаковым успехом компилироваться
> и в Delphi и во FreePascal.
Classes во FreePascal совместим с Delphi. Обратное, вообще говоря, не верно.
> Обёртки для таких примитивных сущностей -- это верх маразма.
Цели обверток:
(1) Придать программе единообразную структуру. Если у нас используются только объекты, то обращения к нативному API немного режут глаз.
(2) Завязка на кроссплатформенность. Если остальной код никак не завязан на особенности OS, то потратил вечер на написание обверток, то в будущем для портирования под другую OS мне понадобится тоже один вечер :)
(3) Type mapping. Постоянные приведения от string к PChar захламляют код. Точно так же и возвращаемые значения
(4) В обвертках также реализовываются наиболее часто встречающиеся сценарии использования объектов. Например, ты сравнивал TThread и BeginThread. Хорошо, отвечу на вопрос, какие преимущества дает стандартный TThread:
(a) Контекст потока. Внутри потомка класса TThread мы можем объявить кучу полей, которые будут в дальнейшем легко доступны во всех вызовах методов TThread. В случае BeginThread контекст прийдется создавать самому: определять структуру, объявлять переменную ctx типа указанной структуры, при всех вызовах передавать эту переменную, любое обращение к переменной контекста предварятьctx.
и т. п.
(b) Метод Synchronize
(c) Стандартный механизм для прерывания вычислений потока. Конечно, я бы предпочел возможность передачи различных сигналов потоку (например, terminate), после чего поток мог бы возбудить исключение, которое я бы обработал в Execute. Или написать функцию вроде RaiseExceptionInThread(Thread: THandle; E: Exception). Но все равно стандартный часто используемый механизм есть.
← →
Eraser © (2008-03-26 13:22) [39]
> DiamondShark © (26.03.08 12:29) [35]
да ООП это вообще зло, а C# - недоязык )
← →
Игорь Шевченко © (2008-03-26 13:27) [40]"ОО-языки упрощают абстракцию, возможно, даже слишком ее упрощают. Они поддерживают создание структур с большим количеством связующего кода и сложными уровнями.
Это может оказаться полезным в случае, если предметная область является
действительно сложной и требует множества абстракций, и вместе с тем такой подход может обернуться неприятностями, если программисты реализуют простые вещи сложными способами, просто потому что им известны эти способы и они умеют ими пользоваться.
Все ОО-языки несколько сколнны "втягивать" программистов в ловушку избыточной иерархии. Чрезмерное количество уровней разрушает прозрачность: крайне затрудняется их просмотр и анализ ментальной модели, которую по существу реализует код. Всецело нарушаются правила простоты, ясности и прозрачности, а в результате код наполняется скрытыми ошибками и создает постоянные проблемы при сопровождении.
Данная тенденция, вероятно, усугубляется тем, что множество курсов по
программированию преподают громоздкую иерархию как способ удовлетворения правила представления. С этой точки зрения множество классов приравнивается к внедрению знаний в данные. Проблема данного подхода заключается в том, что слишком часто "развитые данные" в связующих уровнях фактически не относятся у какому-либо естественному объекту в области действия программы - они предназначены только для связующего уровня.
Одной из причин того, что ОО-языки преуспели в большинстве характерных для них предметных областей (GUI-интерфейсы, моделирование, графические средства), возможно, является то, что в этих областях относительно трудно неправильно определить онтологию типов. Например, в GUI-интерфейсах и графических средствах присутствует довольно естественное соотвествие между манипулируемыми визуальными объектами и классами. Если выясняется, что создается большое количество классов, которые не имеют очевидного соответствия с тем, что
происходит на экране, то, соотвественно, легко заметить, что связующий уровень стал слишком большим."
(с) Эрик Реймонд, "Искусство программирования для Unix"
Страницы: 1 2 вся ветка
Форум: "Прочее";
Текущий архив: 2008.05.11;
Скачать: [xml.tar.bz2];
Память: 0.61 MB
Время: 0.008 c