Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - TThread und Arrays als Rückgabe


ALF - So 25.07.10 21:54
Titel: TThread und Arrays als Rückgabe
Hab nun mein TThread fertig, hoffentlich richtig?
Aber nun, wie gebe ich die Arrays zurück an meine Form?
Alles was ich bisher gelesen habe, habe ich oder konnte ich nicht verstehen oder mit den Arrays umsetzten! Kongret habe ich da auch nichts gefunden!
Mein erster Thread: ich hoffe das es so richtig ist????

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
procedure TScanThread.Execute;
var
  PeakBuf: array[0..176400of integer;  //=1sekunde daten
  Data: ^smallint;
  //lc:integer;
  rc: integer;
  pl, pr: integer;
  BufLen,i: Integer;
  counter: integer;
  peaksL: array of smallint;
  peaksR: array of smallint;
begin
  inherited;
  OutputDebugString('ich arbeite'); //ist nur für mich
  setlength(peaksL, 2600);//max witdh |muss noch genau bestimmt werden;
  setlength(peaksR, 2600);//ist nur zum Test
  counter:= 0;
  pl:= 0;
  pr:= 0; rc:= Fzoom;

  BufLen:= Bass_ChannelGetData(Fdecoder, @PeakBuf, 176400);
  Data:= @PeakBuf;
  while (buflen > 0and (not terminated) do
  begin
    //if xzoom < 6 then
    if (Data^) > pl then pl:= (Data^)else
    if (Data^) < pl then pl:= (Data^);    // Get LeftPeak
    Inc(Data);
    //if xzoom < 6 then
    if (Data^) > pr then pr:= (Data^)else
    if (Data^) < pr then pr:= (Data^);    // Get RightPeak
    Inc(Data);
    BufLen:= BufLen -4 ;

    if counter > 2600 then break;

    peaksL[counter]:= pl;
    peaksR[counter]:= pr;

    while rc > 1 do
    begin
      if (Data^) > pl then pl:= (Data^);//else
      //if (Data^) < pl then pl:= (Data^);
      Inc(Data);
      if (Data^) > pr then pr:= (Data^);//else
      //if (Data^) < pr then pr:= (Data^);
      Inc(Data);
      BufLen:= BufLen -4 ;

      if buflen <= 0 then
      begin
        for i:= low(PeakBuf) to high(PeakBuf) do
        begin
          PeakBuf[i]:= 0;
        end;
        BASS_ChannelSetPosition(Fdecoder, BASS_ChannelSeconds2Bytes(Fdecoder, sec), BASS_POS_BYTE);
        BufLen:= Bass_ChannelGetData(Fdecoder, @PeakBuf, 176400);

        Data:= @PeakBuf;
        inc(sec);

      end;
      dec(rc);
    end;
    inc(counter);
    pl:= 0;
    pr:= 0;
    rc:= trunc(power(2, Fzoom -1));;
  end;
  OutputDebugString('bin Fertig'); // ist nur für mich
  //Edit_Audio.ScanPeaks2(FDecoder, FZoom) das war der alte aufruf;
  //Synchronize(UpdatePeaks);  wie gebe ich die Arrays peaksL +  peaksR zurück?
  Terminate;
end;

Ok,
zum Schluss müsste nun Synchronize aufgerufen werden, so wie man es sagt, aber wie übergebe ich die Arrays??

Gruss Alf
PS.kongret=konkret :wink:


BenBE - So 25.07.10 22:47

Einfahc als Feld innerhalb deiner TThread-Klasse einrichten - innerhalb von Synchronize hast Du dort keine Probleme bzgl. der Synchronisierung.


ALF - So 25.07.10 23:12

Jo, war es das, Fread und oder Fwrithe pl array of smallint oder so ähnlich!
Oder Property ReadArray: array of smallint!

Ich habe schon soviel gelesen kongretes weniger gefunden, Der kopf Qualmt richtig :gruebel: .
Selbst Luckis Tut sagt da nicht viel und in den anderen Foren naja, so richtig um zum testen und zuverstehen nix gefunden!
Selbst wenn es das ist was Du meinst, s.O. dann weis ich immer noch nicht wie ich das ganze aufrufe!?

Gruss Alf


BenBE - So 25.07.10 23:17

BTW: Kongret wird kongret mal anders geschrieben ;-)

Es reicht, wenn Du das ungefähr so baust:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
type TReturnArray = array of Bar;

type
    TFooThread = class(TThread)
    private
        FResultOk: Boolean;
        FResult: TReturnarray;
        //...
    public
        function IsValidResult: Boolean;
        function GetResult: TResultArray;
        //...
    end;

//...

function TFooThread.IsValidResult: Boolean;
begin
    Result := FResultOk;
end;

function TFooThread.GetResult: TResultArray;
begin
    Result := FResult;
end;

//...


ALF - Mo 26.07.10 00:01

Ok hab ich, wenn es so richtig ist?

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
type TReturnArray = array of smallint;

type TScanThread = class(TThread)
  private
    Fdecoder : HSTREAM;
    Fzoom : integer;
    //Fpl, Fpr: array of smallint;//war ein anderer versuch!!!
    FResult: TReturnArray;
  protected
    procedure Execute; override;

  public
    procedure UpdatePeaks(Fpl, Fpr: array of smallint);
    function GetResult: TReturnArray;
                  constructor Create(decoder:HSTREAM; zoom: Integer);
    
  end

....
....

function TScanThread.GetResult: TReturnArray;
begin
  Result := FResult;
end;

Nun hab ich hier ein Denkproblem! Wie erhalten nun die beiden Arrays in Form3 die Werte
wavebufL:= ???
wavebufR:= ???

Sorry meine Unwissenheit. Ich mach dies aber zum ersten mal mit TThreads und wie es nun mal so ist, solange man nicht einmal was umgesetzt hat, ist es nur ein Raten! Wie Wo Was gemacht werden soll, muss. Denn der Anfang, threads erstellen, war ja leicht gefunden und gemacht.
Bitte nicht gleich draufhauhen :flehan: Aber nun geht es leider immer tiefer in diese Materie!
Was ich eigentlich gar nicht vor hatte :shock: Komme aber wahrscheinlich nicht drum herum.

Gruss Alf
PS: kongret=konkret :wink:


BenBE - Mo 26.07.10 00:24

user profile iconALF hat folgendes geschrieben Zum zitierten Posting springen:
Nun hab ich hier ein Denkproblem! Wie erhalten nun die beiden Arrays in Form3 die Werte
wavebufL:= ???
wavebufR:= ???

Naja, halt einfach zwei Felder innerhalb des Thread-Objektes bauen (statt einem Result).

Nehmen wir nun an, dein Thread ruft mit Synchronize nun DisplayStatus auf, dann würdest Du innerhalb von DisplayStatus Dir einfach mit GetResult die Daten holen. Die Zugriffsmethoden hab ich unter der Annahme gebaut, dass DisplayStatus nicht zu deinem Thread gehört. Ansonsten können die auch gerne entfallen. Wie gesagt: Wie Du dort dran kommst, ist egal; wichtig ist nur, dass Du immer nur aus einem Thread drauf zugreifst.

user profile iconALF hat folgendes geschrieben Zum zitierten Posting springen:
PS: kongret=konkret :wink:

#define kongret konkret :wink: - korrekt :P


ALF - Mo 26.07.10 01:55

Danke user profile iconBenBE
Ok hat sich erledigt war doch einfacher als ich dachte!!!!
Nur stehe ich vor dem gleichen Problem wie vorher!!!!
Die Variable aus der Form3 darf nich global sein!!!
Der Thread aber kann nur auf die globale zugreifen, nicht auf die Private!!!

mh... also ein neues Problem!!!

Gruss Alf


jaenicke - Mo 26.07.10 05:50

Der Thread soll auch gar nicht auf irgendwas im Formular zugreifen. Innerhalb von Synchronize sagst du dem Hauptformular Bescheid, zum Beispiel per Event. Dieses läuft dann innerhalb von Synchronize ab und der Hauptthread, sprich dein Formular, kann die Daten über die public-Eigenschaft des Threads abgreifen.


ALF - Mo 26.07.10 12:19

Danke user profile iconGausi hab ich doch echt total schon wieder vergessen!
Man nun kommt doch noch mehr! :? Vermute mal das selbst das noch nicht reicht!!!
Langsam glaube ich das ich doch nur einfache Dinge machen sollte und an die Komplexeren einfach
die Finger weg lasse :(
Gruss Alf


jfheins - Mo 26.07.10 12:44

Es gibt auch das OnTerminate Ereignis von TThread. Du kannst also den Thread starten, das Event zuweisen und dann sobald das Event aufgerufen wird auf das Ergebnsi zurückgreifen!
(Auch wenn der Thread nicht mehr läuft, das Objekt ist noch im Speicher und darf benutzt werden.)

Also in der Form hast du ein Feld für den Thread und ein Event. (Von mir auch beides protected) Beim Erstellen des Threads weist du das Event zu. Und in dem Event kannst du auf den Thred zugreifen.

In dem Thread musst du dann am Ende FResultOk auf Treu setzen und FResult befüllen. Das OnTerminate Event wird automatisch aufgerufen.

btw.: ich würde da noch ne Exception werfen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
type
    TFooThread = class(TThread)
    private
        FResultOk: Boolean;
        FResult: TReturnarray;
        //...
    public
        function IsValidResult: Boolean;
        function GetResult: TResultArray;
        //...
    end;

//...

function TFooThread.IsValidResult: Boolean;
begin
    Result := FResultOk;
end;

function TFooThread.GetResult: TResultArray;
begin
  if not FResultOk then
    raise Exception.Create(...); // Sicher ist sicher

  Result := FResult;
end;

//...


ALF - Mo 26.07.10 14:09

Danke user profile iconjfheins, so hat user profile iconBenBE mir das ja schon aufgezeigt!
Nur, Theorie ist leider das eine. Es ist ja nicht so das ich keine Tuts lese oder in Foren suche!
Wenn man nun an die Umsetzung im eigenen Projekt geht und dies zum ertenmal in Angriff nimmt dann nützt C&P nicht viel. Siehe Dein und Benbe Beispiel. Gut, habe BenBe's Beispiel dann noch einiges angepasst und ergänzt um das ganze erst mal zum laufen zu bekommen, super, stand dann immer noch vor dem Problem, wie komme ich an die Daten??
Leider sind die vielen Beispiel die man findet, immer auf das jeweilige Projekt ausgelegt, so das man keine Vergleichsmöglichkeiten hat!

Nehme ich nur eure Beispiele: TReturnarray;TResultArray;
Ich Frage nun, warum muss ich einen neuen Typ erstellen.
Reicht es nicht wenn die Variable z.B
FArray: array of Smallint,
gleich definiert wird und ich dann damit Arbeite!? Wie ich es dann auch gemacht habe!!!

Und schon steh ich da und frage mich, warum einige es so machen, andere wieder so machen, wie in meinem Beispiel, wo ich dann gesehen habe wie ein anderer es so gelöst hat und ich BenBe verworfen habe. Deins hätte ich dan auch verworfen!
Unabhängig davon das user profile iconGausi mich noch mal daran erinnern musste das mein Vorgehen genau andersrum sein muss!
Wie gesagt Eure Hilfe :zustimm: Ich kann vielleicht nicht so abstrakt denken und scheitere dadurch an die Umsetzung! Oder ich fixiere mich zu sehr, auf das was ich umsetzen möchte und nicht darauf, wie man es umsetzt!
Oder man sollte Pausieren 8)

Besser! Ich bin halt ein langsam denker :mrgreen:
Gruss Alf