Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Delphi Parameterübergabe bei BeginThread für Klassenmethode (https://www.delphipraxis.net/152688-parameteruebergabe-bei-beginthread-fuer-klassenmethode.html)

s.h.a.r.k 2. Jul 2010 01:34

Parameterübergabe bei BeginThread für Klassenmethode
 
Ich habe im Moment eine threoretische Fragen, bei der ich nicht ganz verstehe, warum es denn nicht klappt. Und zwar kann ich via
Delphi-Quellcode:
BeginThread()
ja den Code einer Procedure als Thread ausführen -- das ganze klappt auch wunderbar mit einer Klassenmethode. Nun wollte ich auf Self als Parameter übergeben, was ich auch via [delphi]Pointer(Self)[/delphi) getan habe.

Wenn ich nun eine Klassenmethode via BeginThread ausführe, so bekomme ich es nicht gebacken, Self über den Parameter zu erhalten. Habe ich statt dessen eine (globale) Procedure als Thread-Code, so funktioniert die Übergabe von Self ohne Probleme. Nur warum ist das so? Ich habe in einem Post vorher gelesen, dass das nur so klappt, nur stand da leider keinerlei Begründung.

Hier nochmal etwas Code:
Delphi-Quellcode:
type
TTest = class(TObject)
private
  FThreadHandle : Integer;
  FThreadID : Cardinal;
public
  procedure StartIt();
  procedure ThreadedMethod(Instance: TTest);
end;

procedure ThreadedProcedure(Instance: TTest);

implementation

// --- here the global procedure ---
procedure ThreadedProcedure(Instance: TTest);
begin
  //
  // < ------- Instance = Self parameter
  //
end;

// --- here the class methods ---
procedure TTest.StartIt();
begin
  // i know, i overwrite the handle and id ;)
  FThreadHandle := BeginThread(nil, 0, @ThreadedProcedure, Pointer(Self), 0, FThreadID);
  FThreadHandle := BeginThread(nil, 0, @TTest.ThreadedMethod, Pointer(Self), 0, FThreadID);
end;

procedure TTest.ThreadedMethod(Instance: TTest);
begin
  //
  // < ------- Instance <> Self parameter
  //
end;

SirThornberry 2. Jul 2010 07:48

AW: Parameterübergabe bei BeginThread für Klassenmethode
 
Das ist ganz einfach.
Deine Methode TTest.ThreadedMethod sieht intern so aus:
Delphi-Quellcode:
procedure TTest.ThreadedMethod(Self: TTest; Instance: TTest);
Es gibt also immer als ersten Parameter den unsichtbaren Self-Parameter. Anders ausgedrückt heißt es das deine Methode incompatibel zur erwarteten Funktion ist die eben nur einen Parameter vom Typ Pointer hat. Man sollte sich aber auch nicht darauf verlassen das es in alle Ewigkeit so aussieht das der erste unsichtbare Parameter Self ist. Denn wenn irgendwann mal in einer neuen Version oder bei einem anderen Compiler das ganze intern anders gehandhabt wird funktionieren dann solche hacks nicht mehr:
Delphi-Quellcode:
procedure TTest.ThreadedMethod();
(also das man eine Parameterlose Methode nimmt wohlwissen das der unsichtbare Parameter Self der einzige ist.

himitsu 2. Jul 2010 07:57

AW: Parameterübergabe bei BeginThread für Klassenmethode
 
oder als statische Klassenmethode:
Delphi-Quellcode:
class procedure ThreadedMethod(Instance: TTest); static;
.

Methoden und "nicht-statische" Klassen-Methoden haben eben dieses unsichtbare "Self" mit drin.
> Methode: Self=Objektinstanz
> Klassen-Methode: Self=Klassen-Typ
> statische (static) Klassen-Methode: Self gibt's nicht

SirThornberry 2. Jul 2010 08:06

AW: Parameterübergabe bei BeginThread für Klassenmethode
 
@himitsu? Bist du sicher das es so funktioniert? Ich hab mir den ASM-Code nicht angesehen aber kann es nicht sein das auch bei Klassenmethoden der unsichtbare Self-Parameter existiert? Nur eben nicht als Instanz sondern der Klasse selbst.

[Edit]
@himitus: Hätte ich deinen Beitrag mal zu Ende gelesen so hätte ich mir diesen Beitrag im gesamten hier sparen können :oops:

Deep-Sea 2. Jul 2010 08:07

AW: Parameterübergabe bei BeginThread für Klassenmethode
 
@SirThornberry:
Hat er doch geschrieben?! :-D

s.h.a.r.k 2. Jul 2010 15:51

AW: Parameterübergabe bei BeginThread für Klassenmethode
 
Zitat:

Zitat von SirThornberry (Beitrag 1032980)
Das ist ganz einfach.
Deine Methode TTest.ThreadedMethod sieht intern so aus:
Delphi-Quellcode:
procedure TTest.ThreadedMethod(Self: TTest; Instance: TTest);
Es gibt also immer als ersten Parameter den unsichtbaren Self-Parameter. Anders ausgedrückt heißt es das deine Methode incompatibel zur erwarteten Funktion ist die eben nur einen Parameter vom Typ Pointer hat. Man sollte sich aber auch nicht darauf verlassen das es in alle Ewigkeit so aussieht das der erste unsichtbare Parameter Self ist. Denn wenn irgendwann mal in einer neuen Version oder bei einem anderen Compiler das ganze intern anders gehandhabt wird funktionieren dann solche hacks nicht mehr:
Delphi-Quellcode:
procedure TTest.ThreadedMethod();
(also das man eine Parameterlose Methode nimmt wohlwissen das der unsichtbare Parameter Self der einzige ist.

Gehe ich richtig in der Annahme, dass, mit aktuellem Compiler, es mit einer Methode ohne Parameter funktioniert?!

himitsu 2. Jul 2010 16:03

AW: Parameterübergabe bei BeginThread für Klassenmethode
 
Das ist bei Delphi eigentlich schon immer so, also daß Klassen-Methoden diesen unsichtbaren Parameter haben.
Irgendwo muß je die Information herkommen, um welche Klasse/Instanz es sich handelt, wenn man eine Methode aufruft.

Der TMethod-Zeiger ist auch um diesen Parameter größer.
(Zeiger auf Methode + die Objektinstanz)

s.h.a.r.k 2. Jul 2010 16:16

AW: Parameterübergabe bei BeginThread für Klassenmethode
 
Nur habe ich diese Information immer nur aus dem DP-Forum. An offizieller Stelle habe ich das noch nie gesehen.

himitsu 2. Jul 2010 18:37

AW: Parameterübergabe bei BeginThread für Klassenmethode
 
Offiziell steh halt einiges nirgends.

z.B. sieht
Delphi-Quellcode:
function test: String;
intern eigentlich so aus
Delphi-Quellcode:
procedure test(var Result: String);
Bei einem Integer sieht es aber anders aus.


Ihr könnt ja gerne mal raten, welche Werte von den Messageboxen angezeigt werden ... mal sehn wer alles richtig tippt. :angel:
Delphi-Quellcode:
function Test: String;
begin
  Result := Result + 'abc ';
  raise Exception.Create('buhh');
end;

function Test2: String;
begin
  Result := Result + 'abc ';
end;

function Test3: Integer;
begin
  Result := 1;
  raise Exception.Create('buhh');
end;

function Test4: Integer;
begin
  Result := Result + 1;
end;

procedure TForm1.FormCreate(Sender: TObject);
var S: String;
  i: Integer;
begin
  try
    S := Test;
  except
    // heut ma nix
  end;
  ShowMessage(S);
  S := 'tja ';
  S := Test2;
  S := Test2;
  ShowMessage(S);

  try
    i := Test3;
  except
    // heut ma nix
  end;
  ShowMessage(IntToStr(i));
  i := 10;
  i := Test4;
  i := Test4;
  ShowMessage(IntToStr(i));
end;
PS: Das ist auch ein gutes Beispiel, warum meistens Variablenwerte immer initialisiert werden sollten.

SirThornberry 3. Jul 2010 10:48

AW: Parameterübergabe bei BeginThread für Klassenmethode
 
Zitat:

Zitat von himitsu (Beitrag 1033151)
...Ihr könnt ja gerne mal raten, welche Werte von den Messageboxen angezeigt werden ...

Der Vollständigkeit halber wäre es schön wenn du uns verraten könntest was bei dir angezeigt wird. Denn wenn in 20 Jahren niemand mehr das gleiche Delphi hat wie jenes welches du derzeit benutzt, kann man nur raten ob es in deren Versionen das gleiche ergibt wie bei dir jetzt.

Wie sieht es eigentlich mit der Aufrufkonvention aus? Ist BeginThread eine Api-Funktion? Wenn ja wird doch sicher stdcall oder cdecl erwartet oder?


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:39 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz