Форум: "Начинающим";
Текущий архив: 2008.07.27;
Скачать: [xml.tar.bz2];
ВнизКорректность конструкции при переопределении конструктора Найти похожие ветки
← →
Тын-Дын © (2008-06-24 15:14) [0]Насколько корректна подобная конструкция при определении классов?
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
private
{ Private declarations }
public
{ Public declarations }
end;
TTestThread=class(TThread)
private
FParam: String;
constructor CreateThr(const Param: String);
protected
procedure Execute; override;
public
class function Create(const Param: String): TTestThread;
procedure Terminate;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TTestThread }
class function TTestThread.Create(const Param: String): TTestThread;
begin
try
Result := TTestThread.CreateThr(Param);
except
Result := nil;
end;
end;
constructor TTestThread.CreateThr(const Param: String);
begin
inherited Create(True);
FParam := Param;
FreeOnTerminate := True;
Resume;
end;
procedure TTestThread.Execute;
begin
//
end;
procedure TTestThread.Terminate;
begin
TThread(Self).Terminate;
end;
end.
← →
Тын-Дын © (2008-06-24 15:14) [1]Сорри, не тот тег выставил.
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
private
{ Private declarations }
public
{ Public declarations }
end;
TTestThread=class(TThread)
private
FParam: String;
constructor CreateThr(const Param: String);
protected
procedure Execute; override;
public
class function Create(const Param: String): TTestThread;
procedure Terminate;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TTestThread }
class function TTestThread.Create(const Param: String): TTestThread;
begin
try
Result := TTestThread.CreateThr(Param);
except
Result := nil;
end;
end;
constructor TTestThread.CreateThr(const Param: String);
begin
inherited Create(True);
FParam := Param;
FreeOnTerminate := True;
Resume;
end;
procedure TTestThread.Execute;
begin
//
end;
procedure TTestThread.Terminate;
begin
TThread(Self).Terminate;
end;
end.
← →
Игорь Шевченко © (2008-06-24 15:29) [2]
> procedure TTestThread.Terminate;
> begin
> TThread(Self).Terminate;
> end;
непонятно приведение типа, вместо указания inherited Terminate;
> class function TTestThread.Create(const Param: String):
> TTestThread;
> begin
> try
> Result := TTestThread.CreateThr(Param);
> except
> Result := nil;
> end;
> end;
непонятно, куда девается информация об исключении.
непонятно, куда будет указывать результат, если поток успеет завершиться до возврата управления из конструктора и сработает FreeOnTerminate
То есть, я бы вообще не рекомендовал использовать указатель на объект TThread, если у него задано свойство FreeOnTerminate
← →
Тын-Дын © (2008-06-24 15:34) [3]
> Игорь Шевченко © (24.06.08 15:29) [2]
Terminate, на самом деле, у меня по другому определено.
Это просто пример.
В реальном проекте такой вид:procedure TThrSockClient.Terminate;
begin
FTerminated := True;
PostThreadMessage(ThreadId,WM_QUIT,0,0);
end;
← →
Тын-Дын © (2008-06-24 15:35) [4]Да, и про исключение забыл. Спасибо.
class function TTestThread.Create(const Param: String): TTestThread;
begin
try
Result := TTestThread.CreateThr(Param);
except
Result := nil;
Raise;
end;
end;
← →
Тын-Дын © (2008-06-24 15:37) [5]Но исключение тут только по необходимости.
Возможно такое использование:var
t: TTestThread;
begin
t := TTestThread.Create("Test");
if not Assigned(t) then ...
← →
Игорь Шевченко © (2008-06-24 15:41) [6]Тын-Дын © (24.06.08 15:37) [5]
непонятно, куда будет указывать результат, если поток успеет
завершиться до возврата управления из конструктора и сработает
FreeOnTerminate
> Но исключение тут только по необходимости.
А о причине исключения узнать ?
← →
Тын-Дын © (2008-06-24 16:05) [7]
> Игорь Шевченко c (24.06.08 15:41) [6]
> Тын-Дын c (24.06.08 15:37) [5]
>
> непонятно, куда будет указывать результат, если поток успеет
>
> завершиться до возврата управления из конструктора и сработает
>
> FreeOnTerminate
Ну такая конструкция создаётся для конкретной задачи, поэтому поток не сможет завершиться до выхода из конструктора. но хотелось бы узнать, конечно, подводные камни при таком подходе.
Тогда возможно Resume нужно выполнять в процедуре Create:class function TTestThread.Create(const Param: String): TTestThread;
begin
try
Result := TTestThread.CreateThr(Param);
Result.Resume;
except
Result := nil;
Raise;
end;
end;
> А о причине исключения узнать ?
Это да, если необходимо... Тут можно предусмотреть...
← →
Игорь Шевченко © (2008-06-24 16:16) [8]
> Тогда возможно Resume нужно выполнять в процедуре Create:
наверное. Но в любом случае я не вижу целесообразности возвращать указатель на объект, который может быть удален без ведома в произвольный момент времени.
> except
> Result := nil;
> Raise;
> end;
и какой смысл имеет в этом случае result ?
← →
Игорь Шевченко © (2008-06-24 16:23) [9]Я для создания автоматически уничтожаемых потоков использую простой вызов TAutoFreeThread.Create (params);
когда мне надо узнать о состоянии потока, заводится переменная AutoFreeThreadRunning, соответственно, изменяемая в методе Execute потока. Каковую переменную, без всяких критических секций я опрашиваю, например, по таймеру.
Но у меня потоки такого рода выполняют некие SQL-запросы и заполняют некие DataSet"ы, поэтому результат все равно будет виден глазами, проблем с синхронизацией нету.
← →
Тын-Дын © (2008-06-24 16:27) [10]
> Но в любом случае я не вижу целесообразности возвращать
> указатель на объект, который может быть удален без ведома
> в произвольный момент времени.
В принципе да.
Поток после создания ждёт от других потоков получения некоторых команд (передача/прием данных). В принципе, неуправляемо поток не должен разрушаться, а код хотелось упростить все-таки - потоки будут достаточно часто разрушаться (программированием пула потоков не хочется заморачиваться).
Видимо, сделаюFreeOnTerminate := False;
, тем более, что всё равно придется список объектов хранить где-то.
← →
Тын-Дын © (2008-06-24 16:31) [11]
> и какой смысл имеет в этом случае result ?
Уже убрал-)
← →
Юрий Зотов © (2008-06-24 17:20) [12]> Тын-Дын © (24.06.08 16:31) [11]
> Уже убрал-)
После чего смысл функции Create тоже исчезает.
Почему просто не переопределить конструктор, без всяких извращений?
← →
Тын-Дын © (2008-06-24 17:49) [13]
> Юрий Зотов © (24.06.08 17:20) [12]
> > Тын-Дын © (24.06.08 16:31) [11]
>
> > Уже убрал-)
>
> После чего смысл функции Create тоже исчезает.
>
> Почему просто не переопределить конструктор, без всяких
> извращений?
Ну тогда нужно более подробно задачу объяснить и возникающую проблему.
Изначальная задача:
Есть сервер W2003, на нём RAdmin, Squid-proxy(порт 2222).
На сервере открыто для доступа 2 порта - RDP и 4899(Radmin).
Задача такая:
Radmin пересадить на другой порт(4900), сделать TCP-Mapping с 4899 на 2222.
При этом при подключении клиентом RAdmn на порт 4899 программа должна распознавать сигнатуру RAdmin и маппирование должно производиться на порт 4900.
Реализовать решил в виде сервиса (сейчас простое маппирование сделано на компонентах Indy).
-----------
хм...
Пока писал, мысль пришла, что можно обойтись без дополнительной функции.
Вот как реализовано сейчас:class function TThrSockClient.Create(const Addr: String;
Port: Integer): TThrSockClient;
begin
Result := TThrSockClient.CreateClient(Addr,port);
Result.Resume;
try
Result.WaitStart;
except
Result.Terminate;
Raise;
end;
end;
constructor TThrSockClient.CreateClient(const Addr: String; Port: Integer);
begin
inherited Create(True);
FTag := CreateEvent(nil,True,False,nil);
FPort := 0;
FAddr := Addr;
FPort := Port;
FreeOnTerminate := True;
end;
procedure TThrSockClient.Execute;
var
M: TMsg;
begin
PeekMessage(M,0,0,0,PM_NoRemove);
FSock := TClientSocket.Create(nil);
FSock.OnConnecting := FSockConnecting;
FSock.OnConnect := FSockConnect;
FSock.OnDisconnect := FSockDisconnect;
FSock.OnRead := FSockRead;
FSock.OnWrite := FSockWrite;
FSock.OnError := FSockError;
FSock.Address := FAddr;
FSock.Port := FPort;
SetEvent(FTag);
while (not Terminated) and (GetMessage(M,0,0,0)) do
begin
TranslateMessage(M);
DispatchMessage(M);
end;
end;
procedure TThrSockClient.Terminate;
begin
FTerminated := True;
PostThreadMessage(ThreadId,WM_QUIT,0,0);
end;
procedure TThrSockClient.WaitStart;
begin
try
if WaitForSingleObject(FTag,100)<>WAIT_OBJECT_0 then raise Exception.Create("Error create object");
finally
CloseHandle(FTag);
FTag := 0;
end;
end;
А ведь достаточно в конструкторе сделать так:constructor TThrSockClient.CreateClient(const Addr: String; Port: Integer);
begin
inherited Create(True);
FTag := CreateEvent(nil,True,False,nil);
FPort := 0;
FAddr := Addr;
FPort := Port;
FreeOnTerminate := True;
Resume;
WaitStart;
end;
← →
Юрий Зотов © (2008-06-24 17:55) [14]> Тын-Дын © (24.06.08 17:49) [13]
О чем и речь - просто переопределить конструктор.
← →
Тын-Дын © (2008-06-24 23:51) [15]Спасибо всем.
Кстати, вопрос немного всё-таки другой: не нарушаю ли я какие-либо принципы ООП и есть ли подводные камни при таком замещении предопределённых методов?
← →
Игорь Шевченко © (2008-06-25 00:02) [16]
> Кстати, вопрос немного всё-таки другой: не нарушаю ли я
> какие-либо принципы ООП
принципов всего три - наследование, инкапсуляция и полиморфизм.
> и есть ли подводные камни при таком замещении предопределённых
> методов?
да вроде нету. Компилятор автоматически знает, чьи статические методы вызывать
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2008.07.27;
Скачать: [xml.tar.bz2];
Память: 0.51 MB
Время: 0.008 c