Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Problem mit Thread in der Klasse (https://www.delphipraxis.net/126509-problem-mit-thread-der-klasse.html)

Megamorph 26. Dez 2008 21:54


Problem mit Thread in der Klasse
 
Ich habe leider bei der Verwendung eines Threads in meiner Klasse ein Absturtzproblem, der Compiler meldet weder Warnings noch Fehler. Hier ein Codestück:

Delphi-Quellcode:
type
  TXxxxxxx = class
    private
//...
      bActive_      : Boolean;
    public
//...
      constructor Create;
      procedure WorkThread();
      property bActive : Boolean read bActive_  write bActive_ ;
  end;

implementation

constructor TXxxxxxx.Create;
var
  ThreadID : Cardinal;
begin
//...
  CreateThread(nil, 0, @TXxxxxxx.WorkThread, nil, 0, ThreadID);
end;

procedure TXxxxxxx.WorkThread;
begin
  while true do
  begin
    MessageBox(0,'1','',MB_OK);
    if bActive_ then begin end;
    MessageBox(0,'2','',MB_OK);
  end;
end;

end.
Die erste MessageBox erscheint, dann crasht das Programm. Ich gehe davon aus, dass es ein Problem ist, vom Thread aus auf class member zuzugreifen, was ich jedoch nicht ganz verstehe, da der Thread selbst eine Methode dieser Klasse ist. Ich arbeite mit Delphi7. Wenn mir hier jemand weiter helfen könnte, wäre ich euch sehr verbunden, Danke! (-;
MfG Mega

DP-Maintenance 27. Dez 2008 08:00

DP-Maintenance
 
Dieses Thema wurde von "Matze" von "Programmieren allgemein" nach "Sonstige Fragen zu Delphi" verschoben.
Delphi-Frage

alzaimar 27. Dez 2008 09:35

Re: Problem mit Thread in der Klasse
 
MessageBox und Co sind nicht threadsicher. Du kannst sie also nicht direkt in einem Thread verwenden. Das gilt auch für alle VCL-Komponenten.

Leite deine Klasse von TThread ab und verwende die 'Synchronize'-Methode.

Megamorph 27. Dez 2008 10:01

Re: Problem mit Thread in der Klasse
 
Ich versichere, es liegt nicht an den Messageboxen.

Delphi-Quellcode:
procedure TXxxxxxx.WorkThread;
begin
  while true do
  begin
    MessageBox(0,'1','',MB_OK);
    if bActive_ then begin end;
    MessageBox(0,'2','',MB_OK);
  end;
end;
--> Crash nachdem auf den OK-Button der 1. Messagebox gedrückt wurde

Delphi-Quellcode:
procedure TXxxxxxx.WorkThread;
begin
  while true do
  begin
    MessageBox(0,'1','',MB_OK);
  end;
end;
--> Nach bestätigen kommt immer wieder die selbe Messagebox, kein Crash

Delphi-Quellcode:
procedure TXxxxxxx.WorkThread;
begin
  while true do
  begin
    if bActive_ then begin end;
  end;
end;
--> sofortiger Crash

Hat noch jemand eine Idee?
Thx, Mega.

alzaimar 27. Dez 2008 10:11

Re: Problem mit Thread in der Klasse
 
Bitte, wenn du meinst. :roll: ("Nicht threadsicher" <> "Führt garantiert zum Absturz")

Befolge meinen Rat:
1. Lies nochmal, wie man 'CreateThread' genau aufruft. Dort wird ein Zeiger auf eine Prozedur erwartet, Du übergibst einen Methodenzeiger. Vielleicht liegt es daran.
2. Verwende eine Ableitung der Klasse 'TThread' und erspare Dir Lowlevelfrust.

Megamorph 27. Dez 2008 10:37

Re: Problem mit Thread in der Klasse
 
> Bitte, wenn du meinst. :roll: ("Nicht threadsicher" <> "Führt garantiert zum Absturz")
- MessageBox alleine crasht nicht
- Klassenzugriff alleine crasht
Also liegt es zumindest in diesem Fall am Klassenzugriff. Die Messageboxes habe ich auch nur als Debuggingmittel verwendet, sie sollen im fertigen Programm nicht mehr im Thread laufen.

> 1. Lies nochmal, wie man 'CreateThread' genau aufruft. Dort wird ein Zeiger auf eine Prozedur erwartet, Du übergibst einen Methodenzeiger. Vielleicht liegt es daran.

Ich glaube hier ist der Knackpunkt, bei C++ muss man invoken damit es funktioniert, aber ich habe nicht gefunden, wie man das bei Delphi umsetzt.

> 2. Verwende eine Ableitung der Klasse 'TThread' und erspare Dir Lowlevelfrust.

Habe ich ursprünglich verwendet, aber wie soll ich in der TWorkThread.Execute auf Klassenelemente von TXxxxxxx zugreifen (vermutet nichts Falsches hinter der Klasse, ich habe sie nur unkenntlich gemacht).

Meine vorrübergehende Lösung:

Ich packe den Programmteil, der in einem Thread laufen soll, in eine ganz normale Methode. Diese Methode rufe ich dann im Hauptprogramm nach dem Create des Objekts nach Bauplan der Klasse in einem Thread auf.
Das funktioniert soweit, entspricht aber nicht ganz der Modularität/OOP.
Wenn jemand noch eine Idee hat, wie man in Delphi invoked oder das Problem andersweitig löst, vielen Dank! (:
MfG Mega.

Luckie 27. Dez 2008 11:26

Re: Problem mit Thread in der Klasse
 
Messageboxen sind threadsafe. ShowMessage icst nicht threadsafe, da es zur VCL gehört.

Wenn du trotzdem die API Funktion in einer Klasse verwenden willst, dann musst du aus der Threadfunktion eine Methode machen. Eine Methode einer Klasse hat immer noch einen unsichtbaren Self-Parameter, somit stimmt die Signtur nicht mit der Signatur der Threadfunktion überein. Eine Lösung habe ich hier: http://www.michael-puff.de/Artikel/CallbackMethod.shtml

Desweiteren solltest du nicht CreateThtrrad, sondern BeginThread nutzen. Da BeginThread die globale Variable IsMultithreaded auf true setzt und so den Heap threadsafe macht.

alzaimar 27. Dez 2008 11:45

Re: Problem mit Thread in der Klasse
 
Ah, Luckie. Hups. :oops:

Siehst du, man sieht den Wald vor lauter Bäumen nicht. Du hast eine Klasse deklariert und übergibst einen Methodenzeiger. Obwohl, nee. Das ist gar kein Methodenzeiger, denn da ist ja kein Objekt instantiiert. Innerhalb der Methode greifst Du aber auf eine private Variable der Klasse zu. Ohne Objekt geht das immer in die Hose.

Also nochmal:
Delphi-Quellcode:
Type
  TMyThread = Class (TThread)
    fmyObject : TWhatever;
  protected
    Procedure Execute; Override;
  Public
    Constructor Create (aMyObject : TWhatever);
  End;


Constructor TMyThread.Create (aMyObject : TWhatever);
Begin
  Inherited Create(True); // noch nicht loslaufen;
  fMyObject := aMyObject;
  Resume; // Und ab
End;

Procuedre TMyThread.Execute;
Var
  anotherObject : TMyObject;

Begin
  anotherObject := TMyObject.Create;
  Try
    While Not Terminated Do Begin
      DoSomething (fMyObject);
      DoSomethingElse (anotherObject);
    End
  Finally
    anotherObject.Free;
  End;
End;

...
Begin
  MyObject := TMyObject.Create;
  MyThread := TMyThread.Create (MyObject);
...
  MyThread.Terminate;
  MyThread.WaitFor;
  FreeAndNil (MyThread);
Zitat:

Zitat von Megamorph
... aber wie soll ich in der TWorkThread.Execute auf Klassenelemente von TXxxxxxx zugreifen (vermutet nichts Falsches hinter der Klasse, ich habe sie nur unkenntlich gemacht).

Bist Du sicher, Du weisst, was (Delphi)Klassen sind bzw. wie man damit arbeitet? Oder ist das nur die übliche :wall: Betriebsblindheit? Du musst ein Objekt instantiieren, um auf Klassenelemente zugreifen zu können (Ausnahme: statische Klassenmethoden und statische Klasseneigenschaften).

Megamorph 27. Dez 2008 11:59

Re: Problem mit Thread in der Klasse
 
Hallo,

@Luckie: Danke, genau das habe ich gesucht! So funktioniert es jetzt auch. (-:
@alzaimar:
>Innerhalb der Methode greifst Du aber auf eine private Variable der Klasse zu. Ohne Objekt geht das immer in die Hose.

Ein klares "falsch"! Der Bauplan für ein Objekt ist eine Klasse. Methoden sind Proceduren/Funktionen, die Member der Klasse sind. Methoden können auf interne(private) und externe(public) Variablen (jedoch nicht properties) zugreifen! Das ganze auch ohne Objekt! Logischerweise wird der Code einer Methode einer Klasse erst dann ausgeführt, wenn ein Objekt nach dem Bauplan der Klasse erschaffen wurde und die Methode aufgerufen wird.

Delphi-Quellcode:
type
  TXxxxxxx = class
    private
//...
      bActive_      : Boolean;
    public
//...
      procedure WorkThread();
      property bActive : Boolean read bActive_  write bActive_ ;
  end;

implementation

procedure TXxxxxxx.WorkThread;
begin
  while true do
  begin
    MessageBox(0,'1','',MB_OK);
    if bActive_ then begin end;
    MessageBox(0,'2','',MB_OK);
  end;
end;

end.
Das hier funktioniert, wenn die Methode nun nicht gerade als Thread aufgerufen wird, obwohl die Methode WorkThread (nicht vom Namen irritieren lassen) die private Variable bActive_ benutzt. (-;

>Bist Du sicher, Du weisst, was (Delphi)Klassen sind bzw. wie man damit arbeitet? Oder ist das nur die übliche ouch! Betriebsblindheit?

Bitte nicht nur bei den anderen nach Fehlern suchen.
MfG Mega.

Luckie 27. Dez 2008 12:09

Re: Problem mit Thread in der Klasse
 
Was alzaimar da jetzt meinte, habe ich auch nicht so ganz verstanden. Jedenfalls kann man Klassenmethoden einer Klasse auch aufrufen ohne die zugehörige Klasse zu instanzieren. Dann kann man natürlich nicht auf andere Methoden oder Attribute der Klasse zugreifen, da sie ja nicht existieren, die Klasse wurde ja nicht instanziert und existiert im Speicher nicht. Eventuell meinte alzaimar das. Aber das machst du doch gar nicht, wenn ich das richtig sehe.


Alle Zeitangaben in WEZ +1. Es ist jetzt 20: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