Delphi-PRAXiS
Seite 4 von 5   « Erste     234 5      

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)

Bummi 11. Feb 2011 14:05

AW: Synchronize mit Argumenten
 
Danke Uwe, ich hoffe ich habe es richtig verstanden:
Delphi-Quellcode:
unit Unit2;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;



type
  TProgress = procedure(const Value: integer) of object;

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

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

var
  Form2: TForm2;

implementation

{$R *.dfm}

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

procedure TMyThread.SyncProgress(Value:Integer);
begin
    Queue(
    Procedure
      begin
          FProgress(Value);
      end
    );
end;

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

procedure TForm2.progress(const value: Integer);
begin
  Memo1.Lines.Add('Value: ' + IntToStr(value));
  sleep(500);
end;
end.
Korrekturvorschläge willkommen....

Viktorii 11. Feb 2011 14:13

AW: Synchronize mit Argumenten
 
Also auch mit den Änderungen sieht die Ausgabe bei mir so aus:
Zitat:

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

Bummi 11. Feb 2011 14:16

AW: Synchronize mit Argumenten
 
bei mir so, XE Pro
Code:
Value: 1
Value: 2
Value: 3
Value: 4
Value: 5
Value: 6
Value: 7
Value: 8
Value: 9
Value: 10
mhhhhhhh.....:gruebel:

vielleicht können Uwe oder Sir Rufo uns nochmals auf die Sprünge helfen.

Uwe Raabe 11. Feb 2011 16:05

AW: Synchronize mit Argumenten
 
Der Code von Bummi in #31 ist soweit in Ordnung, bis auf ein paar Kleinigkeiten:

a) das Feld FValue kann entfallen, da es nur noch innerhalb Execute verwendet wird

b) du musst noch etwas tun, damit der Thread nicht beendet wird, bevor die Queues abgearbeitet sind. Das genaue Verhalten ist natürlich von diversen Umständen abhängig, aber bei meinem System fehlt die 10 im Memo, wenn ich das OutputDebugString auskommentiere und es kommt fast gar nichts mehr an, wenn ich das Sleep(200) auch weglasse.

Und Viktorii: Wenn es bei dir nicht geht, hast du vermutlich noch einen Fehler drin. Kann ich ohne aktuelle Sourcen aber nicht erkennen.

Sir Rufo 11. Feb 2011 16:14

AW: Synchronize mit Argumenten
 
Zitat:

Zitat von Viktorii (Beitrag 1081013)
(Das erste mal dass ich mit Generics gearbeitet habe :stupid:)

:wiejetzt:

Seit wann kann Delphi 5 mit Generics umgehen?

Uwe Raabe 11. Feb 2011 16:22

AW: Synchronize mit Argumenten
 
Zitat:

Zitat von Sir Rufo (Beitrag 1081089)
Zitat:

Zitat von Viktorii (Beitrag 1081013)
(Das erste mal dass ich mit Generics gearbeitet habe :stupid:)

:wiejetzt:

Seit wann kann Delphi 5 mit Generics umgehen?

Und TThread.Queue gab's damals auch noch nicht...

Viktorii 11. Feb 2011 17:49

AW: Synchronize mit Argumenten
 
Also wie das Delphi 5 dahinkommt kann ich mir auch nicht erklären :shock:

Hab jetzt mittlerweile auch Delphi XE. Sorry für die Verwirrung.


Was den Code angeht: Kann sein dass ich da einen Bug eingebaut habe. War ein wenig zwischen Tür und Angel getestet.

Wie es aussieht habe ich vor Montag kein Delphi zur Verfügung. Werde es spätestens dann testen.

Schönes Wochenende an alle,

Bummi 11. Feb 2011 18:29

AW: Synchronize mit Argumenten
 
nochmals Danke an Uwe und Sir Rufo

Sir Rufo 11. Feb 2011 18:59

AW: Synchronize mit Argumenten
 
Liste der Anhänge anzeigen (Anzahl: 2)
Sodele, jetzt habe ich mal einen DemoThread inkl. einer Exe zum Ausprobieren.

Mit der Exe kann man schön das Zeitverhalten von Queue und Sync beobachten (auch, dass keine Werte verloren gehen).
Für den Vergleich unter Last gibt es unten den Schalter "Arbeitstimer aktiv". Dieser simuliert eine starke Auslastung vom MainThread.

Interessant ist dabei das Verhalten von Queue und Sync zu sehen.

Den Code-Vorschlag von Uwe habe ich mal eingearbeitet (als SlowSync) und eine kleine Abwandlung (FastSync).
Das Fast und SLow kommt allerdings erst dann zum Tragen, wenn das Event für den Sync nicht zugewiesen ist,
also eigentlich kein Sync erfolgen müsste.

Der Code von Uwe führt aber immer den Sync aus => SlowSync
Mein Code führt den Sync nur aus wenn auch wirklich benötigt => FastSync

Aber ... der Zugriff auf die Prop OnInfoEvent erfolgt beim FastSync noch im ThreadKontext und muss daher entsprechend geschützt sein (siehe Getter von OnInfoEvent).

Der SlowSync kann direkt auf des Feld FOnInfoEvent zugreifen (es sei denn diese Prop würde auch von anderen Thread gelesen/beschrieben, dann muss das eh komplett mit einer CS gesichert werden)

Hier der ThreadCode (Exe und kompletter Source im Anhang):
Delphi-Quellcode:
unit uDemoThread;

interface

uses
  Classes,
  SyncObjs;

type
  TNotifyInfoEvent = procedure( const Info : string; Ticks : Cardinal ) of object;

  TThreadExecType = ( tetSlowSync, tetFastSync, tetQueue );

  TDemoThread = class( TThread )
  private
    { Private-Deklarationen }
    FEventCS :    TCriticalSection;
    FOnInfoEvent : TNotifyInfoEvent;
    FExecType :   TThreadExecType;
    procedure CallSlowSyncEvent( const Info : string; Ticks : Cardinal = 0 );
    procedure CallFastSyncEvent( const Info : string; Ticks : Cardinal = 0 );
    procedure CallQueueEvent( const Info : string; Ticks : Cardinal = 0 );
    function GetOnInfoEvent : TNotifyInfoEvent;
    procedure SetOnInfoEvent( const Value : TNotifyInfoEvent );
  protected
    procedure Execute; override;
  public
    constructor Create( CreateSuspended : Boolean; ExecType : TThreadExecType = tetSlowSync );
    destructor Destroy; override;
  published
    property OnInfoEvent : TNotifyInfoEvent
      read  GetOnInfoEvent
      write SetOnInfoEvent;
  end;

implementation

uses
  SysUtils, Windows;

{ TDemoThread }

procedure TDemoThread.CallSlowSyncEvent( const Info : string; Ticks : Cardinal );
var
  IntTicks : Cardinal;
begin
  // Der SlowSync synchronisiert IMMER mit dem Hauptthread
  // egal, ob ein Event verknüpft ist oder nicht
  // Wenn kein Event verknüpft ist, bräuchte ja eigentlich kein Sync erfolgen
  if MainThreadID = GetCurrentThreadId
  then
    begin
      if Assigned( FOnInfoEvent )
      then
        FOnInfoEvent( Info, Ticks );
    end
  else
    begin
      IntTicks := GetTickCount;
      Synchronize( procedure begin CallSlowSyncEvent( 'via SlowSync: ' + Info, IntTicks ) end );
    end;
end;

procedure TDemoThread.CallFastSyncEvent( const Info : string; Ticks : Cardinal );
var
  IntTicks : Cardinal;
begin
  // Der Fast-Sync synchronisiert nur, wenn auch ein Event zugewiesen wurde
  // Da diese Abfrage aber noch im Thread-Kontext erfolgt, muss die
  // Eigenschaft OnInfoEvent über eine CS abgesichert werden
  if Assigned( OnInfoEvent )
  then
    if MainThreadID = GetCurrentThreadId
    then
      FOnInfoEvent( Info, Ticks )
    else
      begin
        IntTicks := GetTickCount;
        Synchronize( procedure begin CallFastSyncEvent( 'via FastSync: ' + Info, IntTicks ) end );
      end;
end;

procedure TDemoThread.CallQueueEvent( const Info : string; Ticks : Cardinal );
var
  IntTicks : Cardinal;
begin
  // Beim Queue ist es völlig wurscht, ob da nun eine Sync erfolgt oder nicht,
  // denn dieser Aufruf erfolgt eh asynchron und beschäftigt den Thread nicht weiter
  if MainThreadID = GetCurrentThreadId
  then
    begin
      if Assigned( OnInfoEvent )
      then
        FOnInfoEvent( Info, Ticks );
    end
  else
    begin
      IntTicks := GetTickCount;
      Queue( procedure begin CallQueueEvent( 'via Queue: ' + Info, IntTicks ) end );
    end;
end;

constructor TDemoThread.Create( CreateSuspended : Boolean; ExecType : TThreadExecType );
begin
  FEventCS := TCriticalSection.Create;
  FEventCS.Enter;
  try
    inherited Create( CreateSuspended );
    FExecType      := ExecType;
    FreeOnTerminate := True;
  finally
    FEventCS.Leave;
  end;
end;

destructor TDemoThread.Destroy;
begin
  FEventCS.Enter;
  try

    inherited;
  finally
    FEventCS.Leave;
    FreeAndNil( FEventCS );
  end;
end;

procedure TDemoThread.Execute;
var
  idx : Integer;
  Info : string;
begin
  Sleep( 25 );
  { Thread-Code hier einfügen }
  for idx := 0 to 10 do
    begin
      Info := 'Ich bin bei ' + IntToStr( idx );
      case FExecType of
        tetSlowSync :
          CallSlowSyncEvent( Info );
        tetFastSync :
          CallFastSyncEvent( Info );
        tetQueue :
          CallQueueEvent( Info );
      end;
    end;

  // Wenn dieser "Slow"-Sync nicht gemacht wird, kann es sein,
  // dass einige Nachrichten über die Queue verloren gehen!!!!
  case FExecType of
    tetSlowSync: CallSlowSyncEvent( 'Fettich!' );
    tetFastSync: CallFastSyncEvent( 'Fettich!' );
    tetQueue: CallSlowSyncEvent( 'Fettich! (Queue)' );
  end;

end;

function TDemoThread.GetOnInfoEvent : TNotifyInfoEvent;
begin
  FEventCS.Enter;
  try
    Result := FOnInfoEvent;
  finally
    FEventCS.Leave;
  end;
end;

procedure TDemoThread.SetOnInfoEvent( const Value : TNotifyInfoEvent );
begin
  FEventCS.Enter;
  try
    FOnInfoEvent := Value;
  finally
    FEventCS.Leave;
  end;
end;

end.

Viktorii 14. Feb 2011 12:03

AW: Synchronize mit Argumenten
 
So, der Code funktioniert :bounce1:

Jetzt muss ich nur noch das Beispiel von Sir Rufo komplett nachvollziehen :)

Vielen Dank an Alle :thumb:


Alle Zeitangaben in WEZ +1. Es ist jetzt 06:18 Uhr.
Seite 4 von 5   « Erste     234 5      

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