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/)
-   -   Delphi Objekt in Thread und Mainthread verwenden (https://www.delphipraxis.net/149889-objekt-thread-und-mainthread-verwenden.html)

Neutral General 1. Apr 2010 18:26


Objekt in Thread und Mainthread verwenden
 
Hallo,

Also ich habe ein Objekt auf das ich sowohl in einem Thread als auch im MainThread zugreife.
Kann das gutgehen? Dabei muss ich sagen, dass im MainThread nie Methoden aufgerufen werden, die der Thread aufruft.

Ich kann mal ein paar Schnipsel Code zeigen. Wobei der Code in der Execute Methode nicht 1:1 der gleiche ist wie im Original. Aber ggf. kann ich auch den Originalcode posten, wenn das nötig sein sollte.

Delphi-Quellcode:
type
  // Der Thread
  TClientThread = class(TThread)
  private
    // Auf das Objekt wird von anderer Stelle im MainThread zugegriffen
    FClient: TJClient;
  protected
    procedure Execute; override;
  public
    constructor Create(AClient: TJClient); reintroduce;
  end;

// Im MainThread wird niemals auf
// - FClient.Connected
// - FClient.InputBufferIsEmpty
// - FClient.InputBuffer
// - FClient.ReadBytes
// - FClient.FBuffer
// 
// zugegriffen.

procedure TClientThread.Execute;
var Buff: TBytes;
begin
  while not Terminated do
  begin
    if not FClient.Connected then continue;

    if not FClient.InputBufferIsEmpty then
    begin
      FClient.ReadBytes(Buff,FClient.InputBuffer.Size);
      FClient.FBuffer.Write(Buff[0],Length(Buff));
      Synchronize(FClient.ReceiveData);
    end;
    sleep(1);
  end;
end;
Wenn ich Code von TJClient o.ä. posten soll, dann sagt Bescheid.

Gruß
Neutral General

s.h.a.r.k 1. Apr 2010 18:31

Re: Objekt in Thread und Mainthread verwenden
 
Kannst ja jede Methode mit einer CriticalSection sichern, sodass TJClient threadsafe wird. Wichtig dabei ist immer, dass Variable mit einer Setter- und Getter-Methode versehen wird.

himitsu 1. Apr 2010 18:33

Re: Objekt in Thread und Mainthread verwenden
 
Welche Methoden jeweils aufgerufen werden ist egal

Du muß gemeinsam genutzte und nicht threadsichere Variablen/Resourcen gegeneinander absichern.

Beispiel

Delphi-Quellcode:
// threadsave

// Thread 1 greift nur auf Proc zu
// Thread 2 greift nur auf Proc zu

type TMayClass = class
    A, B: Integer;
    procedure ProcA;
    procedure ProcB;
  end;

procedure TMyClass.ProcA;
begin
  Inc(A);
end;

procedure TMyClass.ProcB;
begin
  Inc(B);
end;
Delphi-Quellcode:
// NICHT threadsave

// Thread 1 greift nur auf ProcA zu
// Thread 2 greift nur auf ProcB zu

type TMayClass = class
    X: Integer;
    procedure ProcA;
    procedure ProcB;
  end;

procedure TMyClass.ProcA;
begin
  Inc(X);
end;

procedure TMyClass.ProcB;
begin
  Inc(X);
end;

// aber so wäre es threadsave

var CS: TCriticalSection;

// Thread 1
CS.Enter;
try
  MyClass.ProcA;
finally
  CS.Leave;
end;

// Thread 2 genauso
...
Delphi-Quellcode:
// threadsave

// Thread 1 greift nur auf Proc(1) zu
// Thread 2 greift nur auf Proc(2) zu

type TMayClass = class
    A, B: Integer;
    procedure Proc(i: Integer);
  end;

procedure TMyClass.Proc(i: Integer);
begin
  if i = 1 then Inc(A) else Inc(B);
end;

Neutral General 1. Apr 2010 18:38

Re: Objekt in Thread und Mainthread verwenden
 
Zitat:

Zitat von himitsu
Welche Methoden jeweils aufgerufen werden ist egal

Du muß gemeinsam genutzte und nicht threadsichere Variablen/Resourcen gegeneinander absichern.

Wie mache ich das?

s.h.a.r.k 1. Apr 2010 18:39

Re: Objekt in Thread und Mainthread verwenden
 
Hier findest ein Beispiel.

Hier findest Infos von Luckie zum Thema. Vor allem das Thema Kritische Abschnitte ist hierbei empfehlenswert.

himitsu 1. Apr 2010 18:45

Re: Objekt in Thread und Mainthread verwenden
 
Zitat:

Zitat von Neutral General
Wie mache ich das?

Indem du Aufrufe von FClient, welche gemeinsame Dinge nutzen könnten, z.B. mit einer CriticalSection absicherst.

siehe mein Editiertes: Ende vom zweiten Beispiel

Neutral General 1. Apr 2010 18:48

Re: Objekt in Thread und Mainthread verwenden
 
Ehm also.. das heißt ich mache einfach folgendes:

Delphi-Quellcode:
// als privates Feld z.B.
var CS: TCriticalSection;

procedure TClientThread.Execute;
var Buff: TBytes;
begin
  while not Terminated do
  begin
    CS.Enter;
    try
      if not FClient.FTCPClient.Connected then continue;

      if not FClient.FTCPClient.Socket.InputBufferIsEmpty then
      begin
        FClient.FTCPClient.Socket.ReadBytes(Buff,FClient.FTCPClient.Socket.InputBuffer.Size);
        FClient.FBuffer.Write(Buff[0],Length(Buff));
        Synchronize(FClient.ReceiveData);
      end;
    finally
      CS.Leave;
    end;
    sleep(5);
  end;
end;
und alles ist gut?

s.h.a.r.k 1. Apr 2010 18:50

Re: Objekt in Thread und Mainthread verwenden
 
Also ich hab es immer so verstanden, dass ich das in die entsprechende Methode packe, die von mehrere Threads aufgerufen wird. Wenn ein Thread in die Kritische Sektion eingetreten ist, so muss jeder andere warten, bis dieser diese Sektion wieder verlassen hat.

@himitsu: Bist du sicher, dass das hier passt?
Delphi-Quellcode:
var CS: TCriticalSection;

// Thread 1
CS.Enter;
try
  MyClass.ProcA;
finally
  CS.Leave;
end;

// Thread 2 genauso
...
@Neutral General: Somit wäre dein Code nicht richtig.

wicht 1. Apr 2010 19:30

Re: Objekt in Thread und Mainthread verwenden
 
Neutral General's Code müsste doch klappen, wenn das alles im Thread ist und in der Form auch CS.Enter und Leave am Selben TCriticalSection-Objekt aufgerufen wird?

Tryer 1. Apr 2010 19:44

Re: Objekt in Thread und Mainthread verwenden
 
Zitat:

Zitat von Neutral General
Delphi-Quellcode:
..
        Synchronize(FClient.ReceiveData); //<=========
      end;
    finally
      CS.Leave; //<=========
    end;

Unter der Vorraussetzung das ReceiveData auch per CS.Enter zugreifen will (z.B. auf FBuffer) ist das ein klassischer Deadlock, da der Thread die CS noch hält.

Wenn der MainThread nur auf die in FBuffer bereitgestellten Daten zurückgreift muss auch nur der Zugriff auf FBuffer synchronisiert werden, das schafft mehr Atempausen in denen die einzelnen Threads frei arbeiten können:
Delphi-Quellcode:
    ..
    if not FClient.FTCPClient.Connected then continue;

    if not FClient.FTCPClient.Socket.InputBufferIsEmpty then
    begin
      FClient.FTCPClient.Socket.ReadBytes(Buff,FClient.FTCPClient.Socket.InputBuffer.Size);
      CS.Enter;
      try
        FClient.FBuffer.Write(Buff[0],Length(Buff));
      finally
        CS.Leave;
      end;
      Synchronize(FClient.ReceiveData);
    end;
    ..
Grüsse, Dirk


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