Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Jobliste Kommunikation mit externem Gerät (https://www.delphipraxis.net/80919-jobliste-kommunikation-mit-externem-geraet.html)

DelphiManiac 17. Nov 2006 14:15


Jobliste Kommunikation mit externem Gerät
 
Hallo,

ich bin zurzeit dabei eine Software für ein externen Gerät zu entwickeln.
Dieses Gerät kann sowohl seriell über RS232 als auch USB angesteuert werden angesteuert.
Als USB-Controller ist ein FTDI FT232BM eingebaut.

Nun meine Frage, ich kommuniziere mit dem Gerät folgendermaßen:
Ich habe ein Objekt vom Typ (TGeraet)

Geraet.GetStatus(Status:boolean);
Geraet.GetMesswert(Status:boolean);

Jede Funktion durchläuft bei mir ein Kommunikationsmodul,
dass zB.:
-->den Buffer mit dem Befehl füllt.
-->den Befehl abschicken
-->auf eine Antwort warten (pollen bis 7 Bytes am Port sind)
-->falls 7 Bytes da sind, diese vom Port lesen und bewerten
-->wenn nach einer bestimmten Zeit keine Antwort dann, rausspringen mit Fehlermeldung

Diese Kommunikation läuft bei mir nun im Hauptthread und wenn ich mehrer Befehle (GetXYT, SetSeriennummer....)
ausführe, dann hängt meine Anwendung zeitweise.
Ich habe versucht diese in einen extra Thread zu packen, denn ich von aussen anstosse, aber irgendwie klappt das nicht wie gewollt. Habe auch schon Luckies Tutorial zum Thema Thread gelesen.
Ich würde gerne eine Art Jobliste machen, die in einem Thread abläuft und immerwieder die Jobs (GetXYZ...) abarbeitet
und ich sie von aussen fülle.

Beispiel:
Joblist.Add(Get_YXZ)
Joblist.Add(SetSeriennummer('SN9090');

so dass ich Design von Logik trennen kann und es in einem extra Joblist Thread abläuft.

Hoffentlich könnt ihr mir dabei helfen...
Danke schonmal im Vorraus!!!

Gruß
DelphiManiac

Reinhard Kern 18. Nov 2006 01:34

Re: Jobliste Kommunikation mit externem Gerät
 
Zitat:

Zitat von DelphiManiac
Hallo,

ich bin zurzeit dabei eine Software für ein externen Gerät zu entwickeln.
Dieses Gerät kann sowohl seriell über RS232 als auch USB angesteuert werden angesteuert.
Als USB-Controller ist ein FTDI FT232BM eingebaut.

Nun meine Frage, ich kommuniziere mit dem Gerät folgendermaßen:
Ich habe ein Objekt vom Typ (TGeraet)

Geraet.GetStatus(Status:boolean);
Geraet.GetMesswert(Status:boolean);

Jede Funktion durchläuft bei mir ein Kommunikationsmodul,
dass zB.:
-->den Buffer mit dem Befehl füllt.
-->den Befehl abschicken
-->auf eine Antwort warten (pollen bis 7 Bytes am Port sind)
-->falls 7 Bytes da sind, diese vom Port lesen und bewerten
-->wenn nach einer bestimmten Zeit keine Antwort dann, rausspringen mit Fehlermeldung

Diese Kommunikation läuft bei mir nun im Hauptthread und wenn ich mehrer Befehle (GetXYT, SetSeriennummer....)
ausführe, dann hängt meine Anwendung zeitweise.
Ich habe versucht diese in einen extra Thread zu packen, denn ich von aussen anstosse, aber irgendwie klappt das nicht wie gewollt. Habe auch schon Luckies Tutorial zum Thema Thread gelesen.
Ich würde gerne eine Art Jobliste machen, die in einem Thread abläuft und immerwieder die Jobs (GetXYZ...) abarbeitet
und ich sie von aussen fülle.

Beispiel:
Joblist.Add(Get_YXZ)
Joblist.Add(SetSeriennummer('SN9090');

so dass ich Design von Logik trennen kann und es in einem extra Joblist Thread abläuft.

Hoffentlich könnt ihr mir dabei helfen...
Danke schonmal im Vorraus!!!

Gruß
DelphiManiac

Hallo,

was du als erstes brauchst, ist eine Statusmaschine für jeden Job, etwa in der Art:

Idle - SendHeader - Senddata - SendCRC - WaitforAnswer - RecvHeader - RecvData - RecvCRC

die Events verzweigen dann je nach Status und UnterStatus, z.B. RecvCRC -> CRCByte1, CRCByte2, CRCByte3, CRCByte4, hier werden die CRCs geprüft und wenn Ok -> Idle, usw. usw.

Die Jobliste kann dann den nächsten Job anleiern, wenn der Zustand Idle ist, indem sie das erste Byte in das Transmit Register schreibt und den Zustand auf SendHeader setzt, oder indem sie einen String übergibt (mit Header,Daten,CRC) und einen Writebefehl ans Com-Port schickt und den Status auf Sending setzt - ganz wie das System es erfordert.

Die Statusmaschine(n) sorgen dann selbst dafür, dass ein Job komplett abgewickelt wird, solange kein Fehler auftritt. Zweckmässig ist es, das ganze in eine Matrix aufzunehmen bzw. in eine Sprungtabelle, dann kann man auch keine Kombination vergessen:
Delphi-Quellcode:
  (zur besseren Formatierung)

Event->     Char Sent    Char Recvd   V24Error     Timeout

Status:
Idle        ???           ???           ???           ???      {should not happen}

SendHeader  next Char    rep Error    rep Error    rep Error  
             Header done?  -> Idle      -> Idle      -> Idle
             y->SendData

SendData    next Char    rep Error    rep Error    rep Error  
             Data done?    -> Idle      -> Idle      -> Idle
             y->SendCRC

.....
unvollständig, ich hoffe man erkennt das Prinzip. Zweckmässig ist eine Tabelle mit einer Routine für jede Kombination aus Status und Event. Die ist zugleich eine gute Dokumentation, auch genormte Protokolle werden vorzugsweise mit Statusmaschinen beschrieben.

Gruss Reinhard

Der_Unwissende 18. Nov 2006 10:05

Re: Jobliste Kommunikation mit externem Gerät
 
Zitat:

Zitat von DelphiManiac
Ich habe versucht diese in einen extra Thread zu packen, denn ich von aussen anstosse, aber irgendwie klappt das nicht wie gewollt. Habe auch schon Luckies Tutorial zum Thema Thread gelesen.
Ich würde gerne eine Art Jobliste machen, die in einem Thread abläuft und immerwieder die Jobs (GetXYZ...) abarbeitet
und ich sie von aussen fülle.

Hi,
klingt ein wenig so, als ob etwas dabei nicht ganz geklappt hat (schließe ich aus klappt nicht wie gewollt), aber du sagst nicht was genau anders läuft. Wäre schön wenn du also noch sagen würdest, was du probiert hast und was dabei passiert ist.

An sich denke ich kannst du hier einfach einen Thread nehmen, der eine Methode besitzt, mit der ihm von außen Jobs hinzugefügt werden und ggf. natürlich einer weiteren, die Ergebnisse nach außen reicht.
Dazu wäre der imho sauberste Weg, dass du eine abstrakte Klasse Job schaffst, die einfach eine Methode zum abarbeiten des Jobs besitzt. Ist diese Methode abstrakt, kann jeder Nachfahre sie beliebig implementieren. Der Vorteil ist damit natürlich, dass diese Liste für jede Art von Job geeignet ist.
Die Jobs kannst du dann im Thread in einer TObjectList speichern. Im einfachsten Fall besteht dann die Execute-Methode des Threads einfach nur in einer Endlosschleife, die schaut ob die Job-Liste leer ist und sonst den ersten Job (oder dringensten oder oder) Job aus der Liste nimmt und ausführt. Ok, das Pollen ist an der Stelle nicht so schön, da könntest du sicher auch mit Signalen arbeiten, aber für einen ersten Test dürfte es reichen. Später dann einfach den Thread schlafen legen, so dass der auf ein Signal reagiert, dass du immer dann setzt, wenn du etwas in die Liste einfügst.

Beim einfügen in die Liste solltest du dann unbedingt synchronisieren. Also hier meine ich die Verwendung eines Sperrobjekts, da du insbesondere beim pollen sonst das Problem bekommen kannst, wann ein Objekt eingefügt wurde und wann die Abfrage nach dem Füllstand der Liste erfolgt.

Hoffe ist grob klar, wie ich das meine. Letztlich wäre es aber wichtig zu wissen, was du bisher versucht hast und woran du eigentlich wirklich scheiterst um dir zu helfen. Deshalb erstmal nicht mehr dazu, frag einfach noch mal genauer nach :wink:

Gruß Der Unwissende

DelphiManiac 21. Nov 2006 09:03

Re: Jobliste Kommunikation mit externem Gerät
 
Hallo erstmal super vielen Dank @Reinhard Kern und @Der_Unwissende !!!

@Reinhard Kern:
Das mit der Statusmaschine ist mir leider nicht so ganz klar geworden wie ich soetwas umsetzte


@Der_Unwissende
Danke für deine ausführliche(n) Antwort(en)!!

Nunja ich weiss ehrlich gesagt nicht wie ich so eine Jobliste erstellen soll.
TObjectlist ist ja eine Klasse, die Zeiger speichert, sehe ich doch richtig, oder?

Wenn ich nun meiner Objektliste vom Typ TObjeclist eine Funktion übergeben will, wie mache ich dass denn?
Delphi-Quellcode:
Objekliste.Add(Set_Serialnumber('SeriennummerXYZ'));
:?

Ich habe es zurzeit recht statisch gelöst, aber bin nicht sehr glücklich drüber.

Mein Thread arbeitet statische Lese Methoden ab, je nach Parameter, den ich von aussen vorgebe.

Wenn ich dann eine Schreiboperation abgebe, dann stoppe ich den Thread vorher und lasse ihn dann weiterlaufen. (Dass finde ich sehr unschön)

folgenden Thread-Code habe ich bisher:

Delphi-Quellcode:
procedure TWorkThread.Execute;
(* ----------------------------------------- *)
var
  com: Integer;
  Identifier: Integer;
  I: Integer;
begin
  { Thread-Code hier einfügen }
//  FSTKObj.OnCommunicate:=UpdateCaption;
  isStopped:=false;
  FSTKObj.Get_Device_Identify (Identifier);
{ TODO : LÖSCHEN }
  Identifier:=1000;
  while NOT(Terminated) do
  begin
    fCS.Enter;
      LeseZyklischeDaten;
    fCS.Leave;

  case FCommand of
    STOPP_THREAD:
      begin
        isStopped:=true;
        Self.Suspend;
//        isStopped:=false;
      end;
    READ_HERSTELLERDATEN :
      begin
        Synchronize(ZeigeSandUhr);
        LeseStammdaten;
        Synchronize(UpdateStammdaten);
        if ((FSTKObj.IsMulti) or (FSTKObj.IsMaster)) then
        begin
          fCS.Enter;
          LeseStammdatenMaster;
          Synchronize(UpdateStammdatenMaster);
          fCS.Leave;
        end;
        Synchronize(VersteckeSandUhr);
      end;
    READ_ANALOGOUT :
      begin
        fCS.Enter;
        FSTKObj.Set_CalConfig(false);
        try
          fCS.Enter;
          FSTKObj.Set_CalibDaten(frmMain.editKalibrierwert.Value);
          fCS.Leave;
        except
          fCS.Leave;
          FSTKObj.Set_CalibDaten(0);
        end;
....
Abhängig von FCommand führe ich meine Lesebefehle aus.

Aber ich will ja so eine schöne Jobliste,
der ich auch Schreiboperationen mit Parameter übergabe aus dem Hauptthread übergeben kann.

Vielleicht kannst du mir ja mal ein Code Schnippsel schreiben, wäre super, stehe nämlich ganz schön aufm Schlauch.

DANKE!!!

Der_Unwissende 21. Nov 2006 09:32

Re: Jobliste Kommunikation mit externem Gerät
 
Zitat:

Zitat von DelphiManiac
TObjectlist ist ja eine Klasse, die Zeiger speichert, sehe ich doch richtig, oder?

Nicht ganz. Also ist nicht direkt falsch, aber es sind sehr spezielle Zeiger. Du speicherst vielmehr Referenzen. Eine Referenz ist ein Zeiger auf ein Objekt, und damit halt immer auf einen Nachfahren von TObject. Jedes Objekt muss damit z.B. die Methode Free besitzen, so dass diese Liste den Speicher der Elemente in ihr auch selbst frei geben kann, wenn sie zerstört wird.

An sich ist hier dann die Idee, dass du dir einfach ein Abstraktes BasisObjekt schaffst.

Delphi-Quellcode:
type
  TBaseJob = class(TObject)
    public
      procedure doJob; virtual; abstract;
  end;
Dieses Objekt hat eine Methode doJob, die hier aber abstrakt (nicht implementiert) ist. Du hast somit nur festgelegt, dass jeder Nachfahre eine solche doJob Methode besitzen muss, die irgendwie implemntiert werden kann.
Damit hast du auch schon die Basis für alle Jobs:

Delphi-Quellcode:
type
  TStopJob = class(TBaseJob)
    public
      procedure doJob; override;
  end;

  TReadHerstellerDatenJob = class(TBaseJob)
    public
      procedure doJob; override;
  end;

...

procedure TStopJob.doJob;
begin
  // konkrete Implementierung
end;
...
Ok, soweit hast du erstmal nur eine Menge von Klassen und vielleicht auch eine Menge an Overhead. Wo liegt jetzt also der Sinn? Ganz einfach, du kannst nun eine Liste von TBaseJobs verwalten. Vererbung kann in der Programmierung auch als Erweiterung oder Spezialisierung beschrieben werden. TStopJob und TReadHerstellerDatenJob sind Erben von TBaseJob. Das heißt, dass sie mindestens dass können, was auch TBaseJob kann. Du kannst sie also auch als TBaseJob behandeln. So kann dein TStopJob noch 10 weitere Funktionen haben, behandelst du ihn als TBaseJob, kannst du nur auf die Funktion doJob zugreifen (weil das alles ist, was ein TBaseJob hat). Diese Funktion kann aber natürlich auf alle anderen Funktionen von TStopJob zugreifen und alle Variablen lesen (usw).

So, nun erzeugst du zu einfach die speziellen Jobs, die du benötigst und tust die in eine TObjectList. Die TObjectList speichert hier alles was du reintust als TObject ab. Wenn du also einen Job rausnimmst, musst du ihn casten. Da für alle Jobs eine Basis existiert, castest du in ein TBaseJob (muss für alle Jobs klappen) und rufst von diesem TBaseJob die Methode doJob auf. Damit ist es egal was für einen Job du gerade aus der Liste genommen hast, du musst keine Details über diesen Job kennen, du weißt dass er eine Methode doJob hat und die verwendest du:

Delphi-Quellcode:
// hinzufügen von neuen Jobs:
self.objectList.Add(TStopJob.Create(...));
self.objectList.Add(TReaderHerstellerAngabenJob.Create(...));
self.objectList.Add(TStopJob.Create(...));
...
Delphi-Quellcode:
var buffer : TBaseJob;
// Abarbeitung der Jobs
while (self.objectList.Count > 0) do
begin
  buffer := TBaseJob(self.objectList[0]);
  buffer.doJob;

  self.ojectList.remove(0); //  hier musst du schauen ob die Funktion so heißt, kann auch delete sein
end;
Ja, ist jetzt hier etwas aus eine bestimmten Prozedur rausgenommen, aber ich hoffe die Idee ist so klar.
Die eigentliche Implementierung, wie man einen Job stoppt oder eben hinzufügt steckt nun in den Hüllklassen (Wrapper), hier wären dass TStopJob usw. Die beerben alle eine Basisklasse, die einfach die Signatur einer Methode festlegt, die alle Nachfahren besitzen müssen.
Die JobListe macht wiederum nichts anderes als den ersten enthaltenen Job zu entnehmen und abzuarbeiten. Was für ein Job das genau ist, ist der Liste egal. Die Logik steckt in der Instanz, die diese Methode überschrieben hat.
Diese Vorgehensweise entspricht ein wenig dem Kommando-Pattern.

Gruß Der Unwissende

DelphiManiac 21. Nov 2006 10:34

Re: Jobliste Kommunikation mit externem Gerät
 
@Der_WISSENDE :-)

Hallo, cool, was für eine schnell (und noch dazu ausführliche Antwort)!!

Habe den Ansatz mit den verschiedenen JobKlassen verstanden,

also es gibt eine BasisJobKlasse, die eine nicht implementierte doJob Methode besitzt.
Diese wird in den abgeleiteten Klassen implementiert.

Meine Frage ist jetzt folgende:
ich habe ja eine Klasse die ungefähr 50-60 Kommunikationsmethoden implemetiert:
Beispiel:
Delphi-Quellcode:
TGeraet.Get_Temperatur(var Temp:integer);
TGeraet.Set_Temperatur(Temp:integer);
TGerat.Get_SerialNumber(var SN:String);
TGeraet.Set_SerialNumber(SN:String);
Wie soll ich nun meinem Job sagen, dass er die Funktion Set_Temperatur ausführen soll?
Sollte ich eine Parameterübergabe ( ich benötige ja den Parameter Temp, da ich ihn ja an die Funktion übergeben muss)
per Konstruktor machen, oder wüsstest du eine bessere Methode?

ich habe einige Jobs, die immer (zyklisch) ausgeführt werden müssen, wie z.B.: dass Lesen der Messwerte,
hast du eine Ahnung, wie ich das am besten bewerkstellige, sollte ich einen Timer laufen lassen, der die Jobliste dann wieder und wieder mit dem gleichen Job füllt?

Vielen Dank schonmal für deine Mühe!!
Gruß
DelphiManiac

Der_Unwissende 21. Nov 2006 11:08

Re: Jobliste Kommunikation mit externem Gerät
 
Zitat:

Zitat von DelphiManiac
Wie soll ich nun meinem Job sagen, dass er die Funktion Set_Temperatur ausführen soll?
Sollte ich eine Parameterübergabe ( ich benötige ja den Parameter Temp, da ich ihn ja an die Funktion übergeben muss)
per Konstruktor machen, oder wüsstest du eine bessere Methode?

Also ich würde es einfach über einen Konstruktor machen. Ist der imho einfachste Weg und ich sehe da keinen Nachteil gegenüber anderen Möglichkeiten.

Zitat:

Zitat von DelphiManiac
ich habe einige Jobs, die immer (zyklisch) ausgeführt werden müssen, wie z.B.: dass Lesen der Messwerte,
hast du eine Ahnung, wie ich das am besten bewerkstellige, sollte ich einen Timer laufen lassen, der die Jobliste dann wieder und wieder mit dem gleichen Job füllt?

Hm, klingt auch gut. Also ich meine es ist definitiv ein funktionierender Ansatz, würde ich auch so machen. Sehr viel schönere Lösungen würden mir auch hier nicht einfallen.

DelphiManiac 21. Nov 2006 11:46

Re: Jobliste Kommunikation mit externem Gerät
 
@Der_Unwissende:

Ist die TObjectlist denn Threadsafe, habe nämlich bei der Ausführung ein paar Probleme.

Danke.

Der_Unwissende 21. Nov 2006 11:53

Re: Jobliste Kommunikation mit externem Gerät
 
Zitat:

Zitat von Der_Unwissende
Beim einfügen in die Liste solltest du dann unbedingt synchronisieren. Also hier meine ich die Verwendung eines Sperrobjekts, da du insbesondere beim pollen sonst das Problem bekommen kannst, wann ein Objekt eingefügt wurde und wann die Abfrage nach dem Füllstand der Liste erfolgt.

Um mich mal selbst zu zitieren. Nein, es ist natürlich überhaupt nicht Threadsafe!!! Hätte ich noch mal deutlicher sagen sollen, als ich die Beispiele gepostet habe. Du musst bevor du ein Objekt in die Liste einfügst oder eines entnimmst unbeding ein Speerobjekt verwenden (z.B. TCriticalSection) und wenn du aus dem Thread auf VCL-Komponenten zugreifst, dann musst du dies synchronisieren (im Delphi-Sinne, die Methode synchronize verwenden).

DelphiManiac 21. Nov 2006 12:01

Re: Jobliste Kommunikation mit externem Gerät
 
Hi,

Ja das mit dem Sperrobjekt habe ich mir gedacht.

Reicht es wenn ich ein Sperrobjekt lokal erzeuge (wahrscheinlich nicht, oder)?
oder muss es über jede Unit eingebunden sein?

Wo genau im Code deklariert man denn am besten so ein Sperrobjekt (bzw die CriticalSection).

Danke schonmal :-)

Der_Unwissende 21. Nov 2006 12:36

Re: Jobliste Kommunikation mit externem Gerät
 
Das Speerobjekt brauchst du eigentlich nur in einer Unit, da wo die Liste verwaltet wird. Letztlich muss die Liste ja auch allen die darauf zugreifen bekannt sein. Du könntest dies verhalten z.B. in einer eigenen Unit kapseln (und die Liste umhüllen).
Dann hast einen Wrapper, der dir einfach sagt ob die Liste leer ist, der ein Objekt hinzufügen kann und wenn sie nicht leer ist dir das nächste Objekt zurück gibt. Beim erzeugen dieses Wrappers legst du eine Instanz Variable vom Typ TCriticalSection an, die dann immer gesperrt wird, bevor du ein Element in die Liste tust bzw. aus ihr entfernst:

Delphi-Quellcode:
type
  TJobList = class(TObject)
    private
      FSyncObj : TCriticalSection;
      FList : TObjectList;
    public
      constructor create;
      destructor destrory; override;

      procedure addJob(const Job : TBaseJob);
      procedure getNextJob(out Job : TBaseJob);
      function isEmpty : Boolean;
  end;

// Konstruktor und Destruktor sind klar, erzeugen bzw. freigeben der Objekte

procedure TJobList.addJob(const Job : TBaseJob);
begin
  self.FSyncObj.Acquire;
  self.FList.Add(Job);
  self.FSyncObj.Release;
end;

procedure TJobList.getNextJob(out Job : TBaseJob);
begin
  self.FSyncObj.Acquire;
  Job := TBaseJob(self.FList.Extract(self.FList[0]));
  self.FSyncObj.Release;
end;

function TJobList.isEmpty : Boolean;
begin
  self.FSyncObj.Acquire;
  result := self.FList.Count > 0;
  self.FSyncObj.Release;
end;

DelphiManiac 21. Nov 2006 14:18

Re: Jobliste Kommunikation mit externem Gerät
 
Super klappt alles wie gewollt.

Danke für deine Hilfe!! :angel:

DelphiManiac 23. Nov 2006 09:33

Re: Jobliste Kommunikation mit externem Gerät
 
@Der_Unwissende

Hallo, eine Frage hätte ich noch:

beim jeglichen Zugriff auf die VCL muss man ja synchronisieren, dass ist mir ja klar, da sie nicht Threadsafe ist.

Nun habe ich ja jetzt meine verschiedenen Jobs
wie zb.

ReadMesswerte

In meinem Thread arbeite ich nun die Liste ab:
Delphi-Quellcode:
procedure TJobListThread.Execute;
var
  einJob: TBaseJob;
begin

  { Thread-Code hier einfügen }
  while NOT (Terminated) do
  begin
    If NOT (JobListe.isempty) then
    begin
      JobListe.getNextJob(einJob);
      einJob.doJob;
      Jobliste.deleteJob(einJob);
//      Synchronize(einJob.doJob);
      Sleep(100);
    end;

  end;

end;
Meine Frage nun, ich habe in meiner spezifischen Implementation von
Delphi-Quellcode:
doJob
eine Funktion, die die Einzelnen Messwerte holt und die VCL aktualisiert (Labels...usw) eine Art Observer Pattern.
Wie kann ich denn diesen Zugriff auf die VCL synchronisieren, ich will ja nicht den kompletten Job Synchronisieren,...
dann bräuchte ich ja den Thread nicht :-(.


Vielen Dank

Der_Unwissende 23. Nov 2006 09:50

Re: Jobliste Kommunikation mit externem Gerät
 
Zitat:

Zitat von DelphiManiac
Meine Frage nun, ich habe in meiner spezifischen Implementation von
Delphi-Quellcode:
doJob
eine Funktion, die die Einzelnen Messwerte holt und die VCL aktualisiert (Labels...usw) eine Art Observer Pattern.
Wie kann ich denn diesen Zugriff auf die VCL synchronisieren, ich will ja nicht den kompletten Job Synchronisieren,...
dann bräuchte ich ja den Thread nicht :-(.

Na am einfachsten, in dem du die Aktualisierung der VCL in eine Extra Methode auslagerst. Du hast ja in jedem Job eine bestimmte Anzahl von neuen Messwerten, die du gerne eintragen/anzeigen würdest. Machst du das alles in einem Rutsch, ist die Synchronisation pro VCL-Element wahrscheinlich günstiger, als wenn du hier nach jedem einzelnen Punkt synchronisierst.
Also einfach den Job ausführen, dir merken welche Werte dabei verändert wurden und dann in einer Methode xyz (die dann auch in der abstrakten Klasse verfügbar ist) die VCL Komponenten aktualisieren.

Delphi-Quellcode:
procedure TJobListThread.Execute;
var
  einJob: TBaseJob;
begin

  { Thread-Code hier einfügen } 
  while NOT (Terminated) do
  begin
    If NOT (JobListe.isempty) then
    begin
      JobListe.getNextJob(einJob);
      einJob.doJob;
      Jobliste.deleteJob(einJob);
      synchronize(einJob.xyz);
//      Synchronize(einJob.doJob);
      Sleep(100);
    end;

  end;

end;
Ok, am Namen xyz kann man noch arbeiten :wink:, aber die Idee ist denke ich klar. Du könntest hier z.B. auch einen Datensatz zurückgeben, der alle Messwerte enthält und die GUI kümmert sich selbst um die aktualisierung.
Was deine Messungen angeht, so hätte ich hier mal noch eine Frage, ob du hier wirklich immer alle 100 ms etwas machst? An sich denke ich wäre es schöner, wenn die Jobliste alle Jobs (wenn mal welche in der Liste sind) so schnell wie möglich abarbeitet. Sollte dann eine Pause zwischen zwei Jobs gemacht werden, wäre es irgendwie schöner, wenn man dies hier in den Jobs festlegen kann.
Andererseits gibt es natürlich auch Zeitpunkte an denen die Jobliste keine Jobs beinhaltet, dann sollte natürlich auch der Thread nicht wirklich viel tun, deshalb würde ich dir empfehlen, dass du den Thread immer schlafen legst (self.suspend) und den von außen halt einfach aufweckst, wenn der schläft bevor und du einen Job einfügst.

DelphiManiac 23. Nov 2006 10:26

Re: Jobliste Kommunikation mit externem Gerät
 
@Der_Unwissende
Hi danke,

ja die Idee ist klar.

Eines der Gründe warum ich mich für Delphi als Programmiersprache entschieden habe ist, diese Forum gewesen...
Habe also keinen Fehler gemacht, was das angeht :-D

Meine Jobliste, soll an sich eigentlich immer was zu tun bekommen :-)
Es soll z.B.: immer der Status des Geräts gelesen werden und bestimmte Parameter (Druck/Temp usw) dann kommen je nach angezeigter Maske noch andere Werte hinzu, die ständig, bzw einmalig (Beispiel anzeigen einer Kalbrierungsmaske (einlesen der Kalibrierungswerte)) gelesen werden müssen.

Bin immer noch nach etwa 1 1/2 Jahren dabei ein Programmdesign (wobei ich den Code + Gui und deren maximale Trennung voneinander)
Suche Beispielprojekte, die etwas konkreter sind.
Ich habe im Forum gesehen, dass du dich mit Entwurfsmustern sehr gut auskennst.
Bin auch gerade dabei ein paar Bücher zu wälzen zu einigen Mustern.
Aber wie gesagt, mir fehlt da oft die praktische Anwendung.
Wollte dich mal fragen, ob du mir mal eines deiner Projekte schicken könntest?

Ich weiss ist wahrscheinlich zuviel verlangt, aber irgendwie muss man ja dazulernen.
Um was es in dem Projekt geht ist mir eigentlich egal, es geht mir hauptsächlicht um die Kommunikation von Fachkonzept und GUI.
Vielen Dank ...

Gruß DelphiManiac

Der_Unwissende 23. Nov 2006 12:04

Re: Jobliste Kommunikation mit externem Gerät
 
Zitat:

Zitat von DelphiManiac
Wollte dich mal fragen, ob du mir mal eines deiner Projekte schicken könntest?

Ich weiss ist wahrscheinlich zuviel verlangt, aber irgendwie muss man ja dazulernen.
Um was es in dem Projekt geht ist mir eigentlich egal, es geht mir hauptsächlicht um die Kommunikation von Fachkonzept und GUI.
Vielen Dank ...

Ja, ich verstehe schon was du meinst, dass ist glaube ich auch wirklich eines der Probleme am Programmdesign, man kann es nur mit der Erfahrung verbessern. An sich ist es aber so, dass du nie das perfekte Design von Anfang bis Ende haben wirst, also nicht enttäuscht sein, wenn du an irgendeiner Stelle etwas ändern musst. Die Bücher über die Planung, die Objekt Orientierung, die Entwurfsmuster, ... helfen zwar, aber sie können halt auch nicht mehr leisten als guten Code, den man leicht anpassen kann. Dagegen, dass einige Projekte/Kunden plötzlich doch eine Menge neuer (komplett anderer) Wünsche haben, dagegen kann man nichts tun. Die resultierenden Probleme halten sich damit halt nur stark in Grenzen.
Was ein Projekt angeht, so muss ich dich leider enttäuschen, die wo du ein sauberes Design und eine Halbwegsentkopplung vorfindest sind alles kommerzielle Produkte, an denen hält mein Arbeitgeber bzw. verschiedene Kunden die Copyrights, die darf ich also nicht ohne weitere herausgeben. Ich denke dass verstehst du und wirst das nicht persönlich nehmen. Da ich privat dann immer lieber das leben geniesse als zu programmieren, kann ich dir leider auch hier kein Programm zu schicken.
Ich kann dir nur anbieten dir weiterhin (sogut es geht) bei Entscheidungen eine weitere Meinung zu liefern, wobei ich sagen muss, dass ich genau wie Du und alle anderen auch nur Ideen für's Design habe, es können sich alle gleich irren.

Ich denke das wichtigste für ein gutes Desing ist und bleibt die Einfachheit. Kleine Units, die genau ein Objekt (soweit du OO verwendest) beinhalten (bzw. analog eine bestimmte Funktionalität). Auch dieses Objekt / die Funktionen / Methoden sollten möglichst einfach gehalten sein. Das führt zu wenig Fehlern und verständlichen Code. Möchte man dies konsequent erreichen, führt dass quasi automatisch zur Entkoppelung, da die Darstellung eine andere Funktionalität als die Verwaltung der Daten oder die Logik ist. Design-Pattern helfen hier einfach nur bei dem Verständnis für bestimmte Dinge. Design Entscheidungen sollten immer gut dokumentiert werden, da es sie das Programm ausmachen. Später kann man anhand dieser Entscheidungen leicht nachvollziehen warum das Programm wie aufgebaut ist, was die Wartbarkeit erhöht. Bei den Design-Pattern hat man damit zwei Vorteile:
1. Jmd. hat hier schon ein bestimmtes Problem gelöst
2. Die Lösung ist eindeutig definiert. Verweist man auf ein Pattern ist klar was gemeint ist

Der Rest ist dann noch ein wenig Abstraktion. An sich sollte es bei komplexeren Vorgängen, an denen Verschiedene Objekte beteiligt sind immer einen Controller geben, der zwischen den einzelnen Objekten vermitteln kann. Nur der muss dann alle Objekte kennen, diese sich jedoch nicht. Der Controller kann wiederum mit Abstrakten Klassen oder Interfaces arbeiten, so dass hier die Logik des Controllers unabhängig von der Implementierung der von ihm verwalteten Klassen erhalten bleiben kann. Ja, es ist klar, dass ein Kontroller dann wiederum zwischen Teilsystemen vermitteln kann, wobei der Controller hier nur zwischen anderen Controllern (denen des Teilsystems) vermittelt.

Versucht man diese Prinzipien in eigenen Programmen umzusetzen, so hat man (meiner Erfahrung nach) immer eine recht orgentliche Basis. Wie gesagt, die höchste Priorität hat imho die Einfachheit.

Gruß Der Unwissende


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:25 Uhr.

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