AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

TTask Frage

Ein Thema von DaCoda · begonnen am 24. Mai 2021 · letzter Beitrag vom 27. Mai 2021
Antwort Antwort
DaCoda

Registriert seit: 21. Jul 2006
Ort: Hamburg
165 Beiträge
 
Delphi 12 Athens
 
#1

AW: TTask Frage

  Alt 26. Mai 2021, 12:04
Hallo,
ich komme irgendwie nicht so klar mit TTask/TThread.
Meine Probleme sind:
1. ReadOpcData soll in einen Thread, damit mein Mainprogramm weiter läuft.
2. Wenn ich dann die Maschinen freigebe (Mainprogramm wird beendet) müssen die Tasks/bzw. Threads dann sauber beendet werden.

Ich lande aber irgendwie immer wieder im Chaos (Exceptions, MemoryLeaks etc.) Vielleicht hat ja jemand einen guten Tip, wie ich das am besten Lösen kann...

Die TMaschine ist so definiert:

Code:
unit Kommunikation;

interface
uses
  Globals,
  DataModul,
  tbUtils,
  Winapi.Windows,
  Winapi.Messages,
  System.SysUtils,
  System.Variants,
  System.Classes,
  System.Threading,
  Vcl.Controls,
  Vcl.ExtCtrls,
  Vcl.Forms;

type
  TMaschinenDaten = record
    MaschineOnline: Boolean;

  end;

  TOnDataEvent = procedure(Sender: TObject; Value: TMaschinendaten) of object;

  TMaschine = class(TObject)
  private
    FOwner: TComponent;
    FHostIP: WideString;
    FActive: Boolean;
    PollTimer: TTimer;
    FOpcTask: ITask;
    FOnData: TOnDataEvent;
    FOnTaskStart: TNotifyEvent;
    FOnTaskReady: TNotifyEvent;
    FInterval: Cardinal;
    FMaschinenID: Integer;
    FMaschinenName: WideString;
    FMaschinendaten: TMaschinendaten;

    procedure SetHostIp(Value: WideString);
    procedure SetActive(Value: Boolean);
    procedure SetInterval(Value: Cardinal);
    procedure ReadOpcData;
    procedure OnPollTimer(Sender: TObject);
    procedure OnOpcData(Sender: TObject; Value: TMaschinendaten);
    procedure OnOpcTaskStart(Sender: TObject);
    procedure OnOpcTaskReady(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); virtual;
    destructor Destroy; override;

    property HostIP: WideString read FHostIp write SetHostIp;
    property Active: Boolean read FActive write SetActive;
    property OnData: TOnDataEvent read FOnData write FOnData;
    property OnTaskStart: TNotifyEvent read FOnTaskStart write FOnTaskStart;
    property OnTaskReady: TNotifyEvent read FOnTaskReady write FOnTaskReady;
    property PollInterval: Cardinal read FInterval write SetInterval;
    property MaschinenID: Integer read FMaschinenID write FMaschinenID;
    property MaschinenName: WideString read FMaschinenName write FMaschinenName;
  end;

implementation


(*** TMaschine *********************************************************************************************************************************************************************)

constructor TMaschine.Create(AOwner: TComponent);
begin
  FOwner := AOwner;
  PollTimer := TTimer.Create(FOwner);
  PollTimer.Interval := FInterval;
  PollTimer.OnTimer := OnPollTimer;
  PollTimer.Enabled := False;
end;

destructor TMaschine.Destroy;
begin
  PollTimer.Enabled := False;
  Active := False;
  inherited;
end;

procedure TMaschine.SetInterval(Value: Cardinal);
begin
  FInterval := Value;
  PollTimer.Interval := Value;
end;

procedure TMaschine.OnPollTimer(Sender: TObject);
begin
  ReadOpcData;
end;

procedure TMaschine.SetHostIp(Value: WideString);
begin
  FHostIp := Value;

end;

procedure TMaschine.SetActive(Value: Boolean);
begin
  FActive := Value;
  PollTimer.Enabled := Value;
end;

procedure TMaschine.ReadOpcData;
var
  FirstTickCount: DWord;
begin
  if FActive then begin
    PollTimer.Enabled := False;
    OnOpcTaskStart(Self);
    FOpcTask := TTask.Create(procedure begin

    {*** HIER WERDEN DIE OPC-DATEN DANN GELESEN DIES IST NUR EINE DUMMYROUTINE UM ZEIT ZU VERBRAUCHEN ***}

      FirstTickCount := GetTickCount;
      while ((GetTickCount - FirstTickCount) < 1000) do begin
        Application.ProcessMessages;
        if Application.Terminated then
          Exit;
      end;

    {****************************************************************************************************}

     end);
     FOpcTask.Start;

    OnOpcTaskReady(Self);
    OnOpcData(Self, FMaschinendaten);
    PollTimer.Enabled := True;
  end;
end;

procedure TMaschine.OnOpcTaskStart(Sender: TObject);
begin
  if Assigned(FOnTaskStart) then
    FOnTaskStart(Self);
end;

procedure TMaschine.OnOpcTaskReady(Sender: TObject);
begin
  if Assigned(FOnTaskReady) then
    FOnTaskReady(Self);
end;

procedure TMaschine.OnOpcData(Sender: TObject; Value: TMaschinendaten);
begin
  if Assigned(FOndata) then
    FOnData(Self, FMaschinendaten);
end;

(**********************************************************************************************************************************************************************************)

end.
Mein Hauptprogramm ist in etwa das:

Code:
procedure TfrmMain.FormShow(Sender: TObject);
var
  Loop: Integer;
begin
  SetLength(Maschinen, 10);     //   <- z.B. 10 Maschinen...
  SetLength(Maschinendaten, 10);

  for Loop := Low(Maschinen) to High(Maschinen) do begin
    Maschinen[Loop] := TMaschine.Create(Self);
    try
      Maschinen[Loop].MaschinenID := Loop + 1;
      Maschinen[Loop].OnData := OnOpcData;
      Maschinen[Loop].OnTaskStart := OnTaskStart;
      Maschinen[Loop].OnTaskReady := OnTaskReady;
      Maschinen[Loop].PollInterval := 1000;
      Maschinen[Loop].HostIP := slMaschinenIp.Strings[Loop];
      Maschinen[Loop].MaschinenName := slMaschinenName.Strings[Loop];
      Maschinen[Loop].Active := True;
    except
      // TODO
    end;
  end;

end;

procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
var
  Loop: Integer;
begin
  if High(Maschinen) > -1 then begin
    for Loop := Low(Maschinen) to High(Maschinen) do begin
      if Assigned(Maschinen[Loop]) then begin
        Maschinen[Loop].Active := False;
        FreeAndNil(Maschinen[Loop]);
      end;
    end;
  end;

  CanClose := True;
end;

procedure TfrmMain.OnOpcData(Sender: TObject; Value: TMaschinendaten);
begin
  MaschinenDaten[(Sender as TMaschine).MaschinenID] := Value;
end;

procedure TfrmMAin.OnTaskStart(Sender: TObject);
begin
  // TODO
end;

procedure TfrmMain.OnTaskReady(Sender: TObject);
begin
  //  TODO
end;
Debuggers don’t remove bugs, they only show them in slow-motion.

Geändert von DaCoda (26. Mai 2021 um 14:40 Uhr)
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.073 Beiträge
 
Delphi 10.4 Sydney
 
#2

AW: TTask Frage

  Alt 26. Mai 2021, 13:10
Sehe da weder Threads noch Tasks, nur Timer.
Du erstellst pro TMaschinen-Instanz einen normalen Timer mit 1 Sekunde Intervall.
Bitte poste deinen Quelltext-Versionsstand, mit dem du wirklich Probleme hast.
  Mit Zitat antworten Zitat
DaCoda

Registriert seit: 21. Jul 2006
Ort: Hamburg
165 Beiträge
 
Delphi 12 Athens
 
#3

AW: TTask Frage

  Alt 26. Mai 2021, 14:36
Hallo TiGü,
danke für die Anmerkung. Hatte den falschen Code genommen... Ist jetzt aber korrigiert...
Debuggers don’t remove bugs, they only show them in slow-motion.
  Mit Zitat antworten Zitat
Benutzerbild von TigerLilly
TigerLilly

Registriert seit: 24. Mai 2017
Ort: Wien, Österreich
1.241 Beiträge
 
Delphi 12 Athens
 
#4

AW: TTask Frage

  Alt 27. Mai 2021, 07:24
Ja, das ist nicht so einfach. Ich mache das so, dass ich beim Schließen des Fensters prüfe, ob der Task noch läuft + wenn ja, starte ich einen Timer und unterbreche das beenden. Der Timer schaut dann alle x Sekunden nach, ob der Task schon ferig ist + schließt dann erst das Fenster. Timer deswegen, damit die APP responsiv bleibt.
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
44.340 Beiträge
 
Delphi 12 Athens
 
#5

AW: TTask Frage

  Alt 27. Mai 2021, 11:42
Der Task/Thread bekommt einen Callback mit, und damit sagt er dem Anderen, dass er nun fertig ist. (kann man auch für eine Fortschrittsanzeige nutzen)

Wer nun die Synchronisation durchführt ist egal, also ob Task/Thread vor/um den Callback-Aufruf, oder ob der Andere erst im Callback.
Ein Therapeut entspricht 1024 Gigapeut.
  Mit Zitat antworten Zitat
Benutzerbild von TigerLilly
TigerLilly

Registriert seit: 24. Mai 2017
Ort: Wien, Österreich
1.241 Beiträge
 
Delphi 12 Athens
 
#6

AW: TTask Frage

  Alt 27. Mai 2021, 11:46
Das ist das Problem:
Zitat:
Wenn ich dann die Maschinen freigebe (Mainprogramm wird beendet) müssen die Tasks/bzw. Threads dann sauber beendet werden.
Die Tasks brauchen aber uU noch Zeit, um sich zu beenden bzw sich abzubrechen. Du erfährst beim Beenden, dass der Task noch läuft + kannst das Beenden abbrechen. Oder du wartest mit einem Timer + probierst das Beenden später nochmal.
  Mit Zitat antworten Zitat
Antwort Antwort

 

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 22:01 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz