Wątki i dość nietypowy problem

0

Witam ..

Mam dość nietypowy problem z klasą thread ?


  TWatek = class(TThread)
  private
    //
  protected
    procedure Execute; override;
  public
    FWynik: string;
    constructor create;
    procedure ThreadDone(Sender: TObject);
  end;

constructor TWatek.Create
begin
  inherited Create (true); 
  OnTerminate := ThreadDone; // tu jest moja procedura obsługująca, jej zawartość [ label1.caption := 'done thread'; ]
  FCountTo := '';
end;

procedure TWatek.Execute;
var i: integer;
begin
   FreeOnTerminate := true;
  
   // jakieś obliczenia 
   FWynik := 'Tu przypisuje sobie wynik tych obliczeń ...';
end;

Teraz w kodzie buttona:

var 
  watek: TWatek;
begin
   watek := TWatek.Create; // suspended
   watek.resume;
    
   Caption := watek.FWynik; // Tu powinien byc przypisany wynik .... 

end;

do Captona powinien się przypisać wynik tego mojego wątku ... [ w moim przypadku string ] a nic się nie przypisuje ?? watek.FWynik jest pusty !!!!.
Jeśli ustawie w create mojego wątku FWynik := 'test'; i przypisze tak: Caption := watek.FWynik to do Captiona przypisze test.

Dlaczego nie jest przypisana wartość do zmiennej FWynik w środku procedury execute ??.

[!!!] Ważne jest zeby wynik obliczeń przypisywało do FWynik

Proszę o pomoc w wyjasnieniu tej sytuacji dla mnie dziwnej ?

0

bo najpierw wykonuje się
Caption := watek.FWynik;
a dopiero później
FWynik := 'Tu przypisuje sobie wynik tych obliczeń ...';

0

Ja bym to zrobił w ten sposób

type

TOnResultEvent = procedure(AResult: String) of object; // zadeklarowanie typu procedury

  TWatek = class(TThread)
  private
    FOnResult: TOnResultEvent;
    FResult : String;
  protected
    procedure Execute; override;
    DoOnResult: TOnResultEvent;
  public
    FWynik: string;
    constructor create(OnResult: TOnResultEvent);
    procedure ThreadDone(Sender: TObject);
  end;

constructor TWatek.Create
begin
  inherited Create (true);
  OnTerminate := ThreadDone; // tu jest moja procedura obsługująca, jej zawartość [ label1.caption := 'done thread'; ]
  FCountTo := '';
  FResult := '';
end;

procedure TWatek.Execute;
var i: integer;
begin
   FreeOnTerminate := true;
 
   // jakieś obliczenia
   FResult := 'Tu przypisuje sobie wynik tych obliczeń ...';
   DoOnResult;
end;

procedure TWatek.DoOnResult;
begin
  if Assigned(FOnResult) then
    FOnResult(FResult);
end;

i Potem

private
  procedure Wynik(AResult: String);

{...}

procedure tform1.wynik(aresult: string);
begin
  caption.caption := aresult;
end;

var
  watek: TWatek;
begin
   watek := TWatek.Create(Wyynik); // suspended
   watek.resume;
   
   //Caption := watek.FWynik; // Tu powinien byc przypisany wynik ....
end;
0

Dzieki wam za odpowiedź [!!!] Misiekd i jestem_noob.

Zastanawia mnie jeszcze jedna sprawa... czysto teortyczna - więc jak bym tą klasę TWatek wpakował do osobnego pliku np: Treads.pas
i w tym pliku dodał do głównego Uses Unit1 (reprezentujący Form1) oraz w pliku .dpr to praktycznie moge używać wszystkich komponentów i metod co są zdefiniowane w form1 i unit1.
Problem pojawia sie gdy ten plik Treads.pas dodam do Uses głównej formy ... wywala błąd o tym ze dodanie go spowoduje zapetlenie [..].
Więc postanowilem go zaimplementować w sekcji implementation głównej formy ...

implementation

{$R *.dfm}

Uses Treads;

i błędu o zapętlaniu unitów NIE MA ... ale inna rzecz mnie zastanawia ... jesli zadeklaruje sobie zmienna globalnie

var
  Form1: TForm;
  MojWatek: TWatek;

implementation

{$R *.dfm}

Uses Treads;

to bedzie można używać metod i zmiennych z pliku Thread.pas w deklaracjach funkcji i procedur poniżej - to była globalna definicja ...

A jeżeli ja ją lokalnie zaimplementuje np w buttonie:


implementation

{$R *.dfm}

Uses Treads;

procedure TForm1.Button1Click(Sender: TObject);
var
  MojWatek: TWatek;
begin
   // tu tworzenie class thread ...
end;

to bedzie można używać metod i zmiennych z pliku Thread.pas

[!!!] [!!!] Proszę o wyjaśnienie czy dobrze myśle jak to kompilator widzi ?? .. czy może to i działać ale czy nie bedzie powodować jakichś nadmiernych obciążen procesora włącznie z wywaleniem jakiegoś nieprzewidzianego errora ???

PROSZĘ SIĘ NIE ŚMIAĆ ... trzeba sie też zastanowić nad takimi aspektami

Dzięki Wielkie

0

zmienne deklarowane w metodzie są widoczne TYLKO I WYŁĄCZNIE w tej metodzie. Oczywiście nic nie stoi na przeszkodzie aby zrobić tak
unit1 - to unit z formą
unitThread - to unit z wątkiem
1.

unit unit1;
...
implementation

uses
  unitThread;

var
  watek: TMojWatek;
unit unitThread;

type
  TMojWatek = class(TThread)

  end;

var
  Watek: TMojThread;
...
unit Unit1

implementation

uses
  unitThread;

// i tu masz dostęp do zmiennej Watek z modułu untThread

i jeszcze parę uwag

  1. Wątki mają standardowo zdarzenie OnTerminate, które jest wywoływane po zakończeniu metody execute a przed jego zwolnieniem
  2. z wątku do VCLa można się dostać jedynie przez synchronizację (najprościej używając metody Synchronize)
  3. jeśli chcesz walczyć z wątkami to polecam zapoznać się z klasą rozszerzająca możliwości wątków http://www.delphi.org.pl/zlot/2000/po/adrempack/adrempack.zip
0

Ale checa matko mało ataku serca nie dostalem lista errorów ze hoho i jeszcze troche !!!
ponizej caly unit i bledy ....

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
    procedure Wynik(AResult: String);
  public
    { Public declarations }
  end;


  TOnResultEvent = procedure(AResult: String) of object; // zadeklarowanie typu procedury

  TWatek = class(TThread)
  private
     FOnResult: TOnResultEvent; // [Hint] Unit1.pas(25): H2219 Private symbol 'FOnResult' declared but never used
     FResult : String;
  protected
    DoOnResult: TOnResultEvent;
    procedure Execute; override;
  public
    constructor create(OnResult: TOnResultEvent);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


constructor TWatek.Create(OnResult: TOnResultEvent);
begin
  inherited Create (true);
  FResult := '';
end;


procedure TWatek.Execute;
begin
   FreeOnTerminate := true;

   FResult := 'Tu przypisuje sobie wynik tych obliczeń ...';
   DoOnResult;  // [Error] Unit1.pas(54): E2035 Not enough actual parameters
end;


procedure TWatek.DoOnResult; // [Error] Unit1.pas(58): E2037 Declaration of 'DoOnResult' differs from   previous declaration
begin
  // [Error] Unit1.pas(60): E2003 Undeclared identifier: 'FOnResult'
  // [Error] Unit1.pas(60): E2008 Incompatible types
  // [Error] Unit1.pas(60): E2003 Undeclared identifier: 'FResult'
  if Assigned(FOnResult) then FOnResult(FResult);
end;




///////////////////////////////////////////////////////////

procedure tform1.wynik(aresult: string);
begin
  caption := aresult;
end;



procedure TForm1.Button1Click(Sender: TObject);
var
  watek: TWatek;
begin
   watek := TWatek.Create(Wynik); // suspended
   watek.resume;
end;

Prosze o pomoc !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

0

Wtam przerobilem ten kod od jestem noob :-D jest w nim troche wad ...

// ponizej w komentarzach opisze co jest źle

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
     procedure Wynik(AResult: String); // Tu jest ok!
  public
  end;

A teraz wątek:

  // zadeklarowanie typu jako obiektu - jast ok !!
  TOnResultEvent = procedure(AResult: String) of object; 

  TWatek = class(TThread)
  private
     FOnResult: TOnResultEvent; // Tu też jest ok !!
     FResult : String;
  protected
    // To jest niepotrzebne.  Błąd wywala deklaracja / procedure TWatek.DoOnResult; /
    DoOnResult: TOnResultEvent; // Trzeba usunąc
    procedure Execute; override;
  public
    constructor create; // to  (OnResult: TOnResultEvent); nigdzie nie jest uzywane  mozna usunąć
  Published
    property OnResult: TOnResultEvent read FOnResult write FOnResult; // zastąpimy to tak
  end;

implementation

....


constructor TWatek.Create; // Tak musi byc ...
begin
  inherited Create (true); // Zatrzymany wątek
  FResult := '';
end;


procedure TWatek.Execute;
begin
   FreeOnTerminate := true;

   FResult := 'Tu przypisuje sobie wynik tych obliczeń ...';
   
    OnResult (FResult); // teraz jest property OnResult: TOnResultEvent ... 
   // Błąd wywalało bo nie podalismy parametru ... a poza tym to była procedura ... grrrr 
    
end;

// DELETE
procedure TWatek.DoOnResult; // Usunąć wszystko ten kod jest zły
begin
  if Assigned(FOnResult) then FOnResult(FResult);
end;
// END

procedure tform1.wynik(aresult: string); // ok !!!
begin
  caption := aresult;
end;



procedure TForm1.Button1Click(Sender: TObject);
var
  watek: TWatek;
begin
   watek := TWatek.Create;// usuwamy to (Wynik); pozniej mozna dodać jakies zmienne 
   watek.OnResult := tu_nasza procedura wynik ....
   watek.resume;
end;

1 użytkowników online, w tym zalogowanych: 0, gości: 1