Delphi-PRAXiS
Seite 2 von 5     12 34     Letzte »    

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Synchronize mit Argumenten (https://www.delphipraxis.net/158203-synchronize-mit-argumenten.html)

Viktorii 10. Feb 2011 14:32

AW: Synchronize mit Argumenten
 
Erstmal vielen Dank an alle für die Antworten.

Ich habe den Unterschied zwischen Syncronize und Queue nicht so wirklich verstanden. Und die Hilfe hilft mir beim Verständnis auch nicht wirklich weiter.

Kann mir das jemand mal erläutern wann ich Queue verwenden kann und wann ich es nicht darf?

DeddyH 10. Feb 2011 14:42

AW: Synchronize mit Argumenten
 
Soweit ich es selbst verstanden habe, verhält es sich ähnlich wie bei SendMessage(Synchronize) und PostMessage(Queue): bei Synchronize wartet der Thread, bis der HauptThread die angegebene Methode abgearbeitet hat, bei Queue wird dem HauptThread einfach die Methode "aufs Auge gedrückt", und der Thread läuft weiter. Somit kann bei Verwendung von Queue die Gefahr bestehen, dass der HauptThread nur noch damit beschäftigt ist, die aufgelaufenen Methodenaufrufe abzuarbeiten, nämlich wenn er länger für die Abarbeitung braucht als der Thread. Aber das sind jetzt keine gesicherten Angaben, sondern nur meine Interpretation. Sollte ich mich irren, bitte ich einen Wissenden um Korrektur.

Sir Rufo 10. Feb 2011 14:59

AW: Synchronize mit Argumenten
 
@DeddyH: genau so ist es und genau so steht es in der Hilfe

Zitat:

Zitat von Queue
Führt einen Methodenaufruf im Haupt-Thread asynchron aus.

Zitat:

Zitat von Synchronize
Führt einen Methodenaufruf im Haupt-Thread aus.


Viktorii 10. Feb 2011 15:08

AW: Synchronize mit Argumenten
 
Hmm... Okay. Wenn das denn nun wirklich so ist :-) Wie ist dass dann bei dem Lösungsansatz von DeddyH und Bummi:

Delphi-Quellcode:
procedure TMyOwnThread.SyncError;
begin
  if Assigned(FInstError)
    then FInstError(FError);
end;
 
procedure TMyOwnThread.Execute;
begin
  ...
  // Error 1
  FError := 'Error 1' ;
  Queue(SyncError);
  ...
  // Error 2
  FError := 'Error 2' ;
  Queue(SyncError);
 
  usw.
end;
Wenn Error 1 und Error 2 schnell hintereinander ausgeführt werden und der Hauptthread langsam ist, dann würde FError ja evtl. schon verändert worden sein bevor der Hauptthread FError unter Error 1 ausgelesen hat!?!

Also das typische Problem bei zwei Threads und einer Resource. Also könnte man Critical Sections verwenden. Aber dann wäre man wieder blockieren :drunken:

Da beißt sich die Schlange wieder selbst in den Schwanz :-D

DeddyH 10. Feb 2011 15:18

AW: Synchronize mit Argumenten
 
Ob FError in der Zwischenzeit den Wert geändert hat, dürfte keine Rolle spielen, da die Methode ja bereits mit dem entsprechenden Parameter in die Abarbeitungsschleife des MainThreads gestellt wurde.

Viktorii 10. Feb 2011 15:58

AW: Synchronize mit Argumenten
 
Leider funktioniert es nicht.

Habe mal folgenden Versuch gemacht:

Delphi-Quellcode:
type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    FMyThread: TMyThread;
    procedure progress(value: Integer);
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Memo1.Clear;
  FMyThread := TMyThread.Create(true);
  FMyThread.Progress := progress;
  FMyThread.Resume;
end;

procedure TForm1.progress(value: Integer);
begin
  Memo1.Lines.Add('Value: ' + IntToStr(value));
  sleep(500);
end;
Delphi-Quellcode:
type
  TProgress = procedure(Value: integer) of object;

type
  TMyThread = class(TThread)
  private
    FValue: Integer;
    FProgress: TProgress;
    procedure SyncProgress;
  protected
    procedure Execute; override;
  public
    property Progress: TProgress write FProgress;

  end;

implementation

uses
  Windows, SysUtils;
{ TMyThread }

procedure TMyThread.Execute;
var
  i: Integer;
begin
  for i := 1 to 10 do
  begin
    FValue := i;
    Queue(SyncProgress);
    sleep(200);
    OutputDebugString(PWideChar('FValue: ' + IntToStr(FValue)));
  end;
end;

procedure TMyThread.SyncProgress;
begin
  FProgress(FValue);
end;
Die Ausgabe sieht so aus:
Zitat:

Value: 1
Value: 3
Value: 5
Value: 8
Value: 10
Value: 10
Value: 10
Value: 10
Value: 10
Value: 10
:(

DeddyH 10. Feb 2011 15:59

AW: Synchronize mit Argumenten
 
Und bei Synchronize stimmt das Ergebnis?

Sir Rufo 10. Feb 2011 18:00

AW: Synchronize mit Argumenten
 
Na logisch stimmt das bei Synchronize.

In die Warteschlange kommt ja der Aufruf der Prozedur.
beim Abarbeiten wird die Prozedur ausgeführt.

Und bei der Verwendung von Queue (asynchron) hat sich der Wert von FValue eben schon wieder geändert.
Bei Synchronize schweigt ja alles, bis die Prozedur abgearbeitet wurde.

Für das Queue hilft also auch nur einen WerteQueue (mit CS absichern) die dann Stück für Stück abgearbeitet wird.

Nimm für die WerteQueue eine eigene CS, damit die auch nur dann blockiert ist, wenn dort Werte abgerufen oder eingetragen werden.

Bummi 10. Feb 2011 21:16

AW: Synchronize mit Argumenten
 
@Sir Rufo
Der Zugriff über CS ist sicher sinnvoll, ändert aber nichts daran dass man sich im klaren sein muss wo der Unterschied zwischen Synchronize und Queue liegt und welchen Tod man sterben möchte.
Es wird Anwendungen geben bei es beispielsweise genügt wenn der Hauptthread einen gerade aktuellen Wert zu Anzeige bringt, hier wird Queue der richtige Ansatz sein. Wenn sichergestellt werden muss dass alle Messwerte auflaufen wird es auf Synchonize oder auf z.B. gemeinsam genutzte Array hinauslaufen, bei denen der Thread eine CS gesicherte "gültig bis" Property verwaltet, oder bei einfachen Datentypen direkt Messages.

Sir Rufo 10. Feb 2011 21:54

AW: Synchronize mit Argumenten
 
@Bummi

Wenn man mit Queue arbeitet MUSS man den Zugriff auf die entsprechende Ressource (hier FValue) schützen. Andernfalls riskiert man einen Zugriffsfehler.

Bei Synchronize kann man sich das sparen, da zum Zeitpunkt der Übergabe Thread und Hauptthread im gleichen Threadkontext laufen. Bei Queue eben halt nicht.

Mit einer MessageQueue werden via Queue auch ALLE Nachrichten abgeliefert. Mit nur einer Resoource (hier FValue) natürlich nur der aktuelle Wert zum Zeitpunkt der Abfrage.

Hat man sich also entschlossen mit Queue zu arbeiten (weil man eben nur Daten in den Hauptthread schleusen will und von dem auch nichts direkt zurückhaben will und genau da macht es durchaus Sinn), dann ist eine kleine Liste mit den entsprechenden Nachrichten doch auch kein Problem mehr.

Nur sollte man dabei genau wissen, was man tut, sonst knallt es völlig unkontrolliert (und perverserweise auch nicht regelmäßig und je nach Häufigkeit des Zugriffs auch nicht wirklich oft ... aber es knallt halt :)


Alle Zeitangaben in WEZ +1. Es ist jetzt 03:09 Uhr.
Seite 2 von 5     12 34     Letzte »    

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