Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

использование статического метода [D6, Win2k]


Страницы:   1 2

msgipss ©   (2005-02-03 09:06:00) 

Вопрос ламерский конечно, сорри,
просто всегда считал что в delphi работает такая конструкция:
Ta=object
static procedure b;
end;
..
begin
Ta.b;
А оказалось
Ta=object
procedure b;
end;
var a:Ta;
begin
a.b;

чтож получается, перед тем как использовать статический метод, надо всё же создать экземпляр класса ?
меня можно бить ссылками всякими и др. литературой..


JaDS   (2005-02-04 16:46:00) [1]

позвольте всё же вернуться к начальному вопросу, так как мне он тоже интересен, а именно:


Ta = object
 procedure a;
end;

procedure Ta.a;
begin
 MessageBox(0, 'text', 'caption', 64);
end;


Собственно вопрос, мне надо иметь возможность выполнить код метода без создания экземпляра класса, а именно Ta.b. Замечу что метод статический, к динамическим методам и структурам не обращается. Такое возможно???

PS:
пробовал описывать процедуру с дерективой class - не получилось, или я что-то не так делал. Объявление класса с дерективой class, вместо дерективы object - не предлагать


Erik1   (2005-02-04 12:12:00) [2]

А чем тебя моя procedure MsgWaitFor неустраивает в качестве примера?


msgipss   (2005-02-04 11:36:00) [3]

Спасибо всем участникам ветки.
Последний вопрос, помогите с поиском инфы по сообщениям потоку (PostThreadMessage, PeekMessage), может ламерский пример подкините 8)


Erik1   (2005-02-03 17:02:00) [4]

Дополнительные поля и методы сделаны для менаджера потоков, который их показывает и может убить. У меня запись происходит без участия дополнительного потока и невидно передачи данных, но на основе TCustomThread можеш сделать, что тебе надо. Например записать с буфер с использованием критической секции , а в Excetute(InternalExec у меня) читать от туда, по мере записи очищать считаные данные. У меня есть более интересные примеры с использованием TMultiReadExclusiveWriteSynchronizer, но они сложнее.


Erik1   (2005-02-03 16:52:00) [5]

Ты о самом главном неподумал, как даные от формы помадут в поток? Недолжен поток сам считывать даные, форма сама должна посылать ему. А он в потоке кудато их сохранять. В моем случае в фаил, который закрывается через 5 сек неактивности(что очень удобно). Так происходит вызов:
Log := TLogThread.Create(LogFile, 5000);
Log.LogSave(Format('%d;%d;%d;Channels:%s; %s',[DecNoToInt(Params.Decoder),Params.Cmd,
   fContent, ByteToList(Params.Channels), Buf]));
Но ты хочеш сделать уневерсально для всех форм? Тогда сразу возникает вопрос зачем? Если хочется протоколировать ошибки, то это по другому делается.


msgipss   (2005-02-03 14:46:00) [6]

Verg ©   (03.02.05 13:24) [29]
8), насчет PS cогласен, не программист я, и спасибо за Ваше терпение... теперь можно по вопросам ?
>Вот и непонятно - зачем?
Может я верную идеологию избрал, я хочу фиксировать все события, как штатные, нештатные, критические и т.д которые происходят во всех частях (классах) приложения. Для этой цели создал класс (пусть будет "логер") от треда и там обрабатываю все поступающие сообщения (под обработкой понимается какой то анализ сообщений и действия). Возник вопрос как поставлять сообщения в тред. Сначала я это делал через основной поток (Synchronize), работает нормально но понимаю что это не правильно. Потом попробовал вызывая статический метод логера записывать данные через него.
Затем, подсказали в этой ветке, передать всем классам ссылку на логер и писать с использованием TCriticalSection. Попробовал как Вы сказали - получилось, я просто не дождался вначале 5 сек.
Сейчас Вы сказали про PostThreadMessage, GetMessage, PeekMessage - сейчас буду смотреть.
Вот и всё.. Если есть какие ни будь другие решения самой задачи, хотелось юы услышать (Предыдущий код (от Erik1) не разобрался еще в нем), а по передачи данных между потоками, очень даже помогли спасибо. Если я опять говорю чушь, расскажите пожалуйста.
Заранее благодарен 8)


Verg   (2005-02-03 13:24:00) [7]


> на форме 2 кнопки. button1 их создает. при вводе в Edit1
> записываю во второй поток, который передает это значение
> первому
по переданной ссылке, вот и все... - простая демонстрация...


Вот и непонятно - зачем?

Так ведь можно и третий и четвертый тред создать, и передавать от одного другому, пока последний не сделает то, что мог бы сделать и самый первый в этой надуманной цепочке....
Так почему же их у тебя всего два?  ;)) А не три или четыре?

Ты не в поток записываешь, пойми ты, это поток записывает значение в ячейку (переменную), другой поток ее от туда считывает (когда выспится) и т.д. Все это они делают независимо друг от друга с периодичностью в пять секунд. Почему пять, кстати? Если ты хочешь наладить обмен между потоками, то для этого предусмотрен хотя бы механизм обмена сообщениями (PostThreadMessage, GetMessage, PeekMessage и т.п.). Можно конечно и свой какой-то механизм "навыдумать", основанный на примитивах синхронизации ядра (Event, Mutex) и т.п.
Но, это отдельная тема....


> Я тоже думаю что это ссылка, но в моем примере это не сработало
> и я попробовал так, как написал....


Так ты ж не скзал самого главного:

> что то не получается...


что именно-то?

P.S. Всякие такие определения траблов: "не сработало", "не получается" - это не очень-то подходит для форума программистов.
Я вот тоже попробовал тут телевизор включить: не получается....
Долго разбирался, оказалось - здесь просто нет телевизора....


msgipss   (2005-02-03 13:07:00) [8]

Verg ©   (03.02.05 12:58) [27]
>Я не очень понял философской цели всего этого "проекта" :),
не понял про что Вы 8), про логер (msgipss   (03.02.05 12:35) [23]) или про этот пример ?
Я тоже думаю что это ссылка, но в моем примере это не сработало и я попробовал так, как написал....
Пример демонстрирует следующее, если не понятно...
на форме 2 кнопки. button1 их создает. при вводе в Edit1 записываю во второй поток, который передает это значение первому по переданной ссылке, вот и все... - простая демонстрация...

предыдущий код смотрю...


Verg   (2005-02-03 12:58:00) [9]


> SoftReport1:=TSoftReport1.Create(@SoftReport);


Я не очень понял философской цели всего этого "проекта" :),
Но вот здесь, где @ - очень скверная, на мой взгляд ошибка.
Сам экземпляр класса - это уже ссылка на экземпляр (на участок памяти, где он находится), так что передавая адрес этой ссылкиты добиваешься интерпретации местарасположения SoftReport-ссылки, как собственно местарасположения самого экземпляра TSoftReport.
Что из этого может получится - одному черту известно.

Т.о,

SoftReport1:=TSoftReport1.Create(SoftReport);


msgipss   (2005-02-03 12:57:00) [10]

Erik1 ©   (03.02.05 12:50) [24]
код еще не смотрел, сразу скажу спасибо.
Насчет того что код ерунда и работает в основном потоке - согласен, но он только для того чтобы проверить передачу параметров по ссылке, вот и все - это не рабочий код.
Смотрю код...


Erik1   (2005-02-03 12:50:00) [11]

function TCustomThread.GetDescription: String;
begin
 Result := fDescription;
end;

function TCustomThread.GetGrupp: String;
begin
 Result := IntToStr(ActiveThread);
end;

function TCustomThread.GetID: Integer;
begin
 Result := fID;
end;

{ TLogThread }

procedure TLogThread.BreakThread(Sender: TObject);
begin
 inherited;
 LogClose;
end;

constructor TLogThread.Create(FileName: String; TimeOut: Integer);
begin
 if TimeOut = 0 then
   TimeOut := 5000;
 inherited Create(TimeOut);
 fLogName := FileName;
end;

destructor TLogThread.Destroy;
begin
 LogClose;
 inherited;
end;

procedure TLogThread.LogClose;
begin
 fFileActive := False;
 {$I-}
 Flush(fLog);
 CloseFile(fLog);
 {$I+}
end;

procedure TLogThread.LogSave(const Buf: String);
begin
 if not fFileActive then
 begin
   AssignFile(fLog, fLogName);
   {$I-}
   Reset(fLog);
   {$I+}
   IOResult;
   if not FileExists(fLogName) then
     Rewrite(fLog);

   fFileActive := True;
 end;

 Append(fLog);
 Writeln(fLog, Buf);
end;

procedure TLogThread.WaitTimeOut;
begin
 LogClose;
end;

end.


Erik1   (2005-02-03 12:50:00) [12]

Код полная ерунда, это кажется уже стандарт.
Synchronize(ReadData);
sleep(5000);
У тебя весь поток работает в основном потоке! Разберись с передачей данных, например PostMessage очень полезная вещь. Посмотри примеры в поставке delphi Demos\Threads\thrddemo.dpr

А ладно держи готовый пример:
{-----------------------------------------------------------------------------
Unit Name: DBThreadX
Author:    Erik Ivanov
Date:      07-май-2004
Purpose:
History:   1.0
-----------------------------------------------------------------------------}
unit ThreadBase;

interface
uses  classes, Windows;

type
 PRaiseFrame = ^TRaiseFrame;
 TRaiseFrame = record
   NextRaise: PRaiseFrame;
   ExceptAddr: Pointer;
   ExceptObject: TObject;
   ExceptionRecord: PExceptionRecord;
 end;

 TActiveEvent = (actExit, actSend);
 RAction = record
   Event: array[TActiveEvent] of THandle;
   Call: array[TActiveEvent] of TNotifyEvent;
 end;
 PAction = ^RAction;
 TNotifyEvent = procedure(Data: Pointer) of object;

 TCustomThread = class(TThread)
 private
   fID: Integer;
   fDescription: String;
   fActive: Boolean;
   fTimeOut: Integer;
   fFinished: TNotifyEvent;
   fCall: Integer;
   function  GetID: Integer;
   function  GetDescription: String;
   function  GetGrupp: String;
 protected
   tmEvent: RAction;
   fData: Pointer;
   procedure WaitTimeOut; virtual; abstract;
   procedure ShowMessage(Value: string); dynamic;
   procedure InternalException; dynamic;
   procedure BreakThread(Sender: TObject); dynamic;
   procedure InternalExec(Sender: TObject); virtual;
   procedure Execute; override;
   procedure CreateEvent; dynamic;
   procedure FreeEvent;   dynamic;
   procedure DoFinished;     virtual;
   procedure SetEvent(Value: TActiveEvent);
 public
   fLastException: TObject;
  constructor Create(TimeOut: Integer);
   destructor Destroy; override;
   procedure Start(const Data: Pointer); dynamic;
   procedure Stop; dynamic;
   function  Active: Boolean;

   property  ID: Integer read GetID write fID;
   property  Description: String read GetDescription;
   property  Group: string read GetGrupp;
   property  OnFinished: TNotifyEvent read fFinished write fFinished;
 end;

 TLogThread = class(TCustomThread)
 private
   fFileActive: Boolean;
   fLog: TextFile;
   fLogName: String;
 protected
   procedure WaitTimeOut; override; //virtual;
   procedure BreakThread(Sender: TObject); override;
 public
   constructor Create(FileName: String; TimeOut: Integer);
   destructor Destroy; override;
   procedure LogSave(const Buf: String);
   procedure LogClose;
 end;
 
const
 ActiveThread = MaxInt;

implementation
uses  Messages, sysutils;

procedure MsgWaitFor(Handle: THandle);
Var
   Msg: TMsg;
begin
 while MsgWaitForMultipleObjects(1, Handle, False, INFINITE, QS_ALLINPUT) = WAIT_OBJECT_0 + 1 do
 begin
   PeekMessage(Msg, 0, 0, 0, PM_Remove);
   if Msg.message <> WM_QUIT then  // GetMessage(Msg, 0, 0, 0)
     DispatchMessage(Msg);  //      TranslateMessage(Msg);
 end;
end;

{ TCustomThread }
constructor TCustomThread.Create(TimeOut: Integer);
begin
 inherited Create(True);
 fTimeOut := INFINITE;
   
 fID := Random(MaxInt);
//  New(tmEvent);
 fActive := False;

 tmEvent.Call[actSend] := InternalExec;
 tmEvent.Call[actExit] := BreakThread;

 CreateEvent;
end;

destructor TCustomThread.Destroy;
begin
//  Dispose(tmEvent);
 if Assigned(fLastException) then
   fLastException.Free;
 FreeEvent;
 inherited;
end;

procedure TCustomThread.BreakThread(Sender: TObject);
begin
 Terminate;
end;

procedure TCustomThread.InternalExec(Sender: TObject);
begin
 Inc(fCall);
end;

procedure TCustomThread.DoFinished;
begin
 if Assigned(fFinished) then
   fFinished(fData);
end;

procedure TCustomThread.InternalException;
begin
 if Assigned(fLastException) then
   fLastException.Free;

 if RaiseList <> nil then
 begin
   fLastException := PRaiseFrame(RaiseList)^.ExceptObject;
   PRaiseFrame(RaiseList)^.ExceptObject := nil;
 end
 else
   fLastException := nil;
end;

procedure TCustomThread.Execute;
var
 Status: DWord;
label
 Retry;
begin
 Retry:
 Status := WaitForMultipleObjects(Ord(High(tmEvent.Event)) + 1, @tmEvent.Event,
   false, fTimeOut); //INFINITE

 if fActive and (TActiveEvent(Status) <> actExit) then
   exit;

 fActive := True;
 try
   try
     case Status of
       Ord(Low(TActiveEvent))..Ord(High(TActiveEvent)):
       begin
         tmEvent.Call[TActiveEvent(Status)](Self);
         if (TActiveEvent(Status) <> actExit) then
           Synchronize(DoFinished);
       end;
       WAIT_TIMEOUT: WaitTimeOut;
     else
       OutputDebugString(PChar('Error WaitFor, status:'+IntToStr(Ord(Status))));
     end;
   except
     InternalException;
   end;
 finally
   FActive := False;
 end;

 if not Terminated then
   goto Retry;
end;

procedure TCustomThread.FreeEvent;
var
 i: TActiveEvent;
begin
 for i := Low(tmEvent.Event) to High(tmEvent.Event) do
 begin
   CloseHandle(tmEvent.Event[i]);
 end;
end;

procedure TCustomThread.CreateEvent;
var
 i: TActiveEvent;
begin
 for i := Low(tmEvent.Event) to High(tmEvent.Event) do
 begin
   tmEvent.Event[i] := Windows.CreateEvent(nil, false, false, nil);
 end;
end;

procedure TCustomThread.SetEvent(Value: TActiveEvent);
begin
 Windows.SetEvent(tmEvent.Event[Value]);
end;

procedure TCustomThread.Start(const Data: Pointer);
begin
 fData := Data;
 fCall := 0;
 SetEvent(actSend);
end;

procedure TCustomThread.Stop;
begin
 SetEvent(actExit);
 if Suspended then
   Resume;
 MsgWaitFor(Handle);
end;

function TCustomThread.Active: Boolean;
begin
 Result := fActive;
end;

procedure TCustomThread.ShowMessage(Value: string);
Const   Msg = 'Starvara';
begin
 MessageBox(0, PChar(Msg), PChar(Value), MB_OK);
end;


msgipss   (2005-02-03 12:35:00) [13]

Erik1 ©   (03.02.05 12:23) [21]
да в общем у меня задача простая: хочу фиксировать все события в программе (эдакий логер), для этого создается поток, в который поступает инфа обо всех событиях, там она как то обрабатывается и где надо фиксируется. Может это можно сделать и по другому но я не видел.


msgipss   (2005-02-03 12:31:00) [14]

Verg ©   (03.02.05 10:51) [18]
Спасибо.. так и буду делать, а то до этого передавал (через Synchronize) данные между порожденными потоками через основной поток 8)...

попытался на примере передать ссылку на объект потока в др. поток, что то не получается...
примерный код прилагаю:

type
 TForm1 = class(TForm)
   Memo1: TMemo;
   Button1: TButton;
   Button2: TButton;
   Edit1: TEdit;
   procedure Button1Click(Sender: TObject);
   procedure Button2Click(Sender: TObject);
 private
 public
 end;

    TSoftReport = class(TThread) // Объявление основного класса
     private
        fDetail:Byte;
        procedure SetDetail(value:byte);
     protected
        procedure ReadData;
        procedure Execute; override;
     public
      constructor Create;
      property Detail:byte read fDetail write SetDetail;
    end;

    TSoftReport1 = class(TThread) // Объявление класса (таких будет много)
     private
        fDetail:Byte;
        SoftReport:TSoftReport;
        procedure SetDetail(value:byte);
     protected
        procedure Execute; override;
     public
      constructor Create(p:Pointer);  // передаем ссылку на объект первого класса
      property Detail:byte read fDetail write SetDetail;
    end;

var   Form1: TForm1;
     SoftReport:TSoftReport;
     SoftReport1:TSoftReport1;
implementation
{$R *.dfm}

constructor TSoftReport.Create;
begin
fDetail:=0;
inherited Create(False);
end;

procedure TSoftReport.SetDetail(value:byte);
begin
  fDetail:=value;
end;

procedure TSoftReport.Execute;
begin
  while not Terminated do
  begin
     Synchronize(ReadData);
     sleep(5000);
  end;
end;

procedure TSoftReport.ReadData;  // показываем текущее состояние примера
begin
 Form1.Memo1.Lines.Add(intToStr(fDetail));
end;

//_____________________________________________________________________________________________

constructor TSoftReport1.Create(p:pointer);
begin
fDetail:=0;
SoftReport:=p;      // хочу так получить объект
inherited Create(False);
end;

procedure TSoftReport1.SetDetail(value:byte);
begin
  fDetail:=value;
end;

procedure TSoftReport1.Execute;
begin
  while not Terminated do
  begin
     SoftReport.Detail:=fDetail;   // записываем данные в другой поток
     sleep(5000);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
  SoftReport:=TSoftReport.Create;  // создаем поток 1
  SoftReport1:=TSoftReport1.Create(@SoftReport); // создаем поток 2 и передаем ссылку на второй
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
  SoftReport1.Detail:=strToint(edit1.Text); // пытаемся проверить пример передачи данных по ссылке
end;

помогите пожалуйста с передачей параметра


Erik1   (2005-02-03 12:23:00) [15]

Да гремучея смесь у тебя в голове, все вместе WinApi для работы с тредами, обращение к VCL(Synchronize) и еще классы. Ты бы определился с чем работаеш, а то все сразу изучать, голова лопнет.


Digitman   (2005-02-03 11:09:00) [16]


> что будет если множество потоков одновременно ломануться
> изменять property моего класса 1


это смотря что у тебя фактически творится в объекте при обращении к его св-ву для записи или чтения последнего ..


Verg   (2005-02-03 11:00:00) [17]


> Synchronize


Это существет только для синхронизации действия потока с действиями потока его создавшего (назовем его главным), путем дачи указаний (постановки некоей заявки в его, для этого предназначенную очередь таких заявок) главному потоку выполнить некий код (метод) в тот момент, в который ему (главному) покажется, что это сделать он не проч.
Этот "главный" и выполняет заявки всех порожденных им потоков в порядке той самой очереди и только в определенные им самим "фазы" своего исполнения.
Эта фаза - как правило фаза выборки сообщений из своей системной очереди (перед/после PeekMessage).


Verg   (2005-02-03 10:51:00) [18]

Во многих случаях для совместного доступа нескольких потоков к сложным структурам данных, когда предпологается некое "нестабильное" по отношению к другим потокам их состояние в процессе этого доступа к ним, используют CriticalSection. Т.е. процедура (метод) доступа к некоему property класса 1 использует нечто типа

procedure TThreadOfClass1.SetMyProperty( Value : TPropertyValue );
begin
  CriticalSection.Enter;
  try
    MyProperty := Value; // Это абстрактный пример, здесь может быть какие-то
                                 // и довольно сложные манипуляции
  finally
    CriticalSection.Leave;
  end;
end;

Главное, чтобы все потоки "ходили" к этому property только через этот "шлюз".
CryticalSection - это private поле класса TThreadOfClass1, которое создается в его конструкторе ( убивается, соотв. в деструкторе).


msgipss   (2005-02-03 10:40:00) [19]

Verg ©   (03.02.05 10:10) [16]

8)) не отрицаю, запутался.. или опять неверно объяснился.
1. пишу класс от TThread, добавляю свои property или опять не то говорю ?
2. создаю от него (от класса) объект (в приостановленном виде)
3. вызываю метод Resume, т.е. запускаю поток в работу

4. создаю группу других объектов (классы которых порождены тоже от TThread), при создании этих объектов, им передается ссылка на объект 1.
5. при своей работе группа объектов 4, вызывает property объекта 1.

Внимание вопрос: правильно ли так делать, потому как у каждого класса порожденного от TThread, есть Synchronize, для работы с др.потоками. И еще, если это возможно, что будет если множество потоков одновременно ломануться изменять property моего класса 1

По моему все понятно спросил...


Verg   (2005-02-03 10:10:00) [20]


> в смысле вызывать его свойства и методы


У потока нет свойств или методов.
Свойства или методы есть у структур данных - классов.

> 15] msgipss   (03.02.05 10:02)


С внешним миром можно общаться не только посредством "пропросить что-то сделать другой поток" (Synchronize).

"Несколько по-другому, правильно ли это" - насколько по-другому сделано правильно, на столько правильно это и есть :)

P.S. Ощущение, как от электрика окончательно запутавшегося в проводах....


Страницы:   1 2

Наверх

Титульная страница Поиск, карта сайта Написать письмо