Einzelnen Beitrag anzeigen

norwegen60

Registriert seit: 23. Dez 2007
Ort: Schwarzwald
505 Beiträge
 
Delphi 12 Athens
 
#1

Allgemeine Fragen zu Threads

  Alt 25. Jan 2017, 14:17
Delphi-Version: 10 Seattle
Hallo

ich habe mal ausgehend von dem Beispiel in http://docwiki.embarcadero.com/CodeE...dList_(Delphi) folgenden (sinnfreien) Code geschrieben. Ich weiß z.B. dass es besser wäre, in der Memo nur die fehlenden Werte zu ergänzen. Ich wollte den Code aber flach halten:
Delphi-Quellcode:
unit fo_ThreadListDePraxis;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Generics.Collections,
  Vcl.Samples.Spin;

type
  TForm1 = class(TForm)
    laSleeptime: TLabel;
    Memo1: TMemo;
    Button1: TButton;
    Button2: TButton;
    SpinEdit1: TSpinEdit;
    Label1: TLabel;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure Button2Click(Sender: TObject);
    procedure SpinEdit1Change(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

  TMyList = class(TList<Integer>)
  end;

  TMyThread = class(TThread)
  private
    FCounter, FSleepTime: Integer;
  protected
    procedure Execute; override;
  public
    property SleepTime: Integer read FSleepTime write FSleepTime;
  end;

var
  Form1: TForm1;
  MyList: TMyList;
  MyThread: TMyThread;

implementation

{$R *.dfm}

procedure TForm1.Button2Click(Sender: TObject);
begin
  if assigned(MyThread) then
  begin
    MyThread.Terminate; // Setzt MyThread nicht auf NIL, d.h. nächster Button2Click führt wieder in diesn Block
    Button2.Caption := 'Start Thread';
  end
  else
  begin
    Button2.Caption := 'Terminate Thread';
    MyThread := TMyThread.Create(true); // Create suspended--secondProcess does not run yet.
    MyThread.FreeOnTerminate := true; // You do not need to clean up after termination.
    MyThread.SleepTime := SpinEdit1.Value;
    MyThread.Resume; // Now run the thread.
  end;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  MyList.Free;
  MyThread.Terminate;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  MyList := TMyList.Create;
end;

procedure TForm1.SpinEdit1Change(Sender: TObject);
begin
  if assigned(MyThread) then
    MyThread.SleepTime := SpinEdit1.Value;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i: Integer;
begin
  for i := 0 to 20 do
    MyList.Add(random(200));
end;

{ TMyThread }

procedure TMyThread.Execute;
var
  i: Integer;
begin
  inherited;

  while (true) do
  begin
    if Terminated then
      exit;

    inc(FCounter);
    Form1.Label1.Caption := IntToStr(FCounter);
    Form1.Memo1.Clear;

    System.TMonitor.Enter(MyList); // Liste gegen Zweitzugriff sperren. Muss das sein?
    try
      for i := 0 to MyList.Count - 1 do
      begin
        if Terminated then
          exit;
        Form1.Memo1.Lines.Add(format('%d: %d', [i, MyList.Items[i]])); // Ist das zulässig?
      end;
    finally
      System.TMonitor.exit(MyList); // Sperrung der Liste wieder aufheben
    end;
    sleep(FSleepTime); // FSleepTime oder besser SleepTime?
  end;
end;

end.
Meine Fragen:
  1. Überall heißt es man soll aus Threads nicht direkt auf Form-Elemente zugreifen. Hier wird es doch gemacht. Also doch kein Problem wenn sicher ist dass kein anderer auf Form1.Memo1 zugreift? Und abgesehen davon dass es sauberer ist die Trennung per Synchronize zu machen?
  2. Im Execute greife ich auf die globale Liste MyList zu. Muss ich die zwingend mit System.TMonitor.Enter sperren wenn ich nur lesen will?
    • Was kann passieren wenn ich nur Werte hinzufüge?
    • Was wenn sich auch Werte ändern könnten?
  3. Obwohl ich MyThread.FreeOnTerminate := true; gesetzt habe funktioniert die Assign-Abfrage in procedure TForm1.Button2Click(Sender: TObject) . Setze ich einen Haltepunkt nach dem Terminate ist MyThread nicht NIL.
  4. Die Anwendung wirft in der IDE eine Exception wenn in FormClose MyThread.Terminate; nicht aufgerufen wird. Muss ich beim Beenden sonst noch was beachten?
  5. Greift man innerhalb einer Klasse besser auf die Variable oder das Property zu (FSleepTime oder SleeptTime)?

Danke für euer Feedback
Gerd

Geändert von TBx (25. Jan 2017 um 15:41 Uhr) Grund: Habe dem Threadtitel ein r spendiert
  Mit Zitat antworten Zitat