AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein warum verlangsamen diese beiden Funktionen meinen Thread?
Thema durchsuchen
Ansicht
Themen-Optionen

warum verlangsamen diese beiden Funktionen meinen Thread?

Ein Thema von BAMatze · begonnen am 25. Sep 2009 · letzter Beitrag vom 25. Sep 2009
Antwort Antwort
BAMatze

Registriert seit: 18. Aug 2008
Ort: Berlin
759 Beiträge
 
Turbo Delphi für Win32
 
#1

warum verlangsamen diese beiden Funktionen meinen Thread?

  Alt 25. Sep 2009, 13:54
Hallo und guten Tag an alle DP´ler

Mal wieder eine kleine Verständnisfrage. Und zwar werden einige Änderungen am ComPorts überwacht und sollen auf einer Form dargestellt werden. Dies funktioniert zumindest auch, allerdings verlangsamt dies mein Programm erheblich und blockiert es zumindest für 2-3 Sekunden (z.B. bei einem Klick auf der Form ändert sich das Checked einer Checkbox nicht sofort.

Hier mal alle relevanten Funktionen. Die Refresh der Formen (welche ich denke, dass sie mich am meisten behindern, hab ich schon versucht mit hilfe von boolschen Variablen deutlich zu verringern):

Delphi-Quellcode:
procedure TControlCardControlThread.Execute;
var c, iIndex: integer;
begin
  for iIndex := 1 to 5 do (Form3.findcomponent('CheckBox' + inttostr(iIndex+8)) as TCheckBox).Checked:= fabDigChannelSignals[iIndex];
  repeat
  c := GetTickCount;
  Synchronize(UpdateForm3);
  c := {interval}50 - (GetTickCount - c);
  if c > 0 then Sleep(c);
until Terminated;
if assigned(FsLComport) then FsLComport.Free;
end;

{////////////////////////////////////////////////////////////////////////////////////}
{/                           Interaktion mit Oberfläche                             /}
{////////////////////////////////////////////////////////////////////////////////////}

// bei dieser Form sollte festgestellt werden, ob sich irgendwas verändert hat und
// nur bei vorhandenen Änderungen sollte auch Refreshed werden. Ständiges neuzeichnen
// führt zum ausbremsen des TThreads!
procedure TControlCardControlThread.UpdateForm3;
var i: integer;
    bGeneralDigChannelInput, bCriticalDigChannelInput, bUpdateDataForm1, bUpdateDataForm3: boolean;
begin

  bUpdateDataForm1 := ComportSearch(FsLComport);

  bUpdateDataForm3 := false;
  bgeneralDigChannelInput := false;
  bcriticalDigChannelInput := false;
  for i := 1 to 5 do
    begin
      case not(FabDigChannelSignals[i] xor Board.digEingang[i]) of
      false: begin
               bUpdateDataForm3 := true;
               DoSingleDigChannelInput(i);
               bGeneralDigChannelInput := true;
               if i in [2..4] then bcriticalDigChannelInput := true;
               FabDigChannelSignals[i] := Board.digEingang[i];
               (Form3.findcomponent('CheckBox' + inttostr(i+8)) as TCheckBox).Checked:= fabDigChannelSignals[i];
             end;
      end;
      
      if (i in [1..2]) and ((Form3.findcomponent('ProgressBar' + inttostr(i)) as TProgressBar).Position <> Board.anaEingang[i]) then
        begin
          (Form3.findcomponent('ProgressBar' + inttostr(i)) as TProgressBar).Position := Board.anaEingang[i];
          bUpdateDataForm3 := true;
        end;
    end;
  if bUpdateDataForm3 then Form3.Refresh; // <-- Änderung nur refresh, wenn Änderung vorhanden sind
  if FbBlinkRedLight then Board.RedLight := not Board.RedLight;
  if bGeneralDigChannelInput then doGeneralDigChannelInput;
  if bCriticalDigChannelInput then doCriticalDigChannelInput;
  // Hier ebenso Änderungen überprüfen und nur bei vorhandenen Änderungen das neuzeichnen
  // auslösen!
  if bUpdateDataForm1 then
    begin
      Form1.Memo1.Clear;
      Form1.Memo1.Lines := FsLComport;
      Form1.Refresh;
    end;

  case Counter of
  0: Form3.StatusBar1.Panels[0].Text := '/';
  1: Form3.StatusBar1.Panels[0].Text := '|';
  2: Form3.StatusBar1.Panels[0].Text := '\';
  3: Form3.StatusBar1.Panels[0].Text := '-';
  end;
  Counter := Counter + 1;
  if Counter > 3 then Counter := 0;
end;

{////////////////////////////////////////////////////////////////////////////////////}
{/                              Überwachungsfunktion                                /}
{////////////////////////////////////////////////////////////////////////////////////}

// In eine Funktion umarbeiten, die true zurückgibt, wenn keine Änderungen vorhanden sind
// oder false wenn Änderungen vorhanden sind.
function TControlCardControlThread.ComportSearch(var List: TStringList):boolean;
var ComBuffer: TComport;
    TempLineArray: array of Integer;
    bLine: boolean;
    i, j: integer;
begin
  ComBuffer := TComport.Create;
  result := false;
  try
    SetLength(TempLineArray,0);
    for i := 0 to ComBuffer.Anzahl - 1 do
      begin
        j := List.IndexOf(inttostr(ComBuffer.Comportnummer[i]));
        case j of
        -1: begin
              result := true;
              List.Add(inttostr(ComBuffer.Comportnummer[i])); // Eintrag ist noch nicht vorhanden -> Eintrag wird hinzugefügt
              SetLength(TempLineArray,Length(TempLineArray)+1);
              TempLineArray[Length(TempLineArray)-1] := List.IndexOf(inttostr(ComBuffer.Comportnummer[i]));
            end;
        else
          begin
            SetLength(TempLineArray,Length(TempLineArray)+1);
            TempLineArray[Length(TempLineArray)-1] := j;
          end;
        end;
      end;
    //in Temp Linearray sind jetzt alle Zeilen Nummern der StringList enthalten, die
    //auch in der Comport-Liste vorhanden sind. Nun müssen die überflüsigen Zeilen nur gelöscht werden
    for i := 0 to List.Count -1 do
      begin
        bLine := false;
        for j := 0 to Length(TempLineArray) do if i= TempLineArray[j] then bLine := true; // Zeile ist in TempLineArray vorhanden und soll somit NICHT gelöscht werden!
        if not bLine then
          begin
            List.Delete(i); //Wenn die Zeile nich in TEmpLineArray vorhanden ist, muss der Comport geschlossen worden sein und kann somit aus der Liste gelöscht werden.
            result := true;
          end;
      end;
  finally
    SetLength(TempLineArray,0);
    ComBuffer.Free;
  end;
end;
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Hier noch die Comport-Klasse:

Type TComport = class
  private
    bPorts: boolean;
    FsLComports: TStringList;
    function ComPort(ComPortNummer: byte): longbool;
    function ComportScan: boolean;
    function GetComport(index: integer): integer;
    function GetAnzahl: integer;
  public
    constructor Create; reintroduce;
    destructor destroy; override;
    property verfuegbarePorts: boolean read bPorts;
    property Comportnummer[Index: integer]: integer read GetComport;
    property Anzahl: integer read GetAnzahl;
end;

Constructor TComport.Create;
begin
  inherited create;
  FsLComports := TStringlist.Create;
  bPorts := ComportScan;
end;

destructor TComport.Destroy;
begin

  FsLComports.Free;
  inherited destroy;
end;

function TComport.GetComport(index: Integer): integer;
begin
  result := strtoint(FsLComports[Index]);
end;

function TComport.GetAnzahl;
begin
  result := FsLComports.Count;
end;

// Funktion, die überprüfft, ob an der Comschnittstelle mit der Nummer "ComPortNummer"
// ein Gerät angeschlossen ist (ob eine Kommunikation geöffnet ist) oder nicht.
function TComport.ComPort(ComPortNummer: byte): longbool;
var TestHandle : integer;
begin TestHandle :=CreateFile(PChar('\\.\COM'+IntToStr(ComPortNummer)),GENERIC_READ or GENERIC_WRITE,0,
                              nil,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,LongInt(0));
  if (TestHandle <= 0) then Result := false
  else begin Result := true; CloseHandle(TestHandle); end;
end;
// Funktion, die alle ComPorts bis zu einer vom Programmierer festgelegten maximal
// ComPortnummer anspricht.
function TComport.ComportScan: boolean;
var i: integer;
    aBuffer: array of Integer;
begin
  for i := 0 to 20 do if ComPort(i) then FsLComports.Add(inttostr(i));
  if FsLComports.Count = 0 then result := false
  else result := true;
end;
Also der Fehler sollte immer meiner Meinung nach immer noch daran liegen, dass er zuviel macht, sehe aber gerade nicht, wo ich die Interaktion zwischen Thread und Formen noch NICHT eingeschränkt habe, wenn keine Änderung vorliegt.

Hoffe ihr könnt mir wieder helfen
BAMatze
2. Account Sero
  Mit Zitat antworten Zitat
Tryer

Registriert seit: 16. Aug 2003
200 Beiträge
 
#2

Re: warum verlangsamen diese beiden Funktionen meinen Thread

  Alt 25. Sep 2009, 14:09
Also mit fällt nichts besonderes auf, darum nur ein paar Ideen:

- FindComponent kannst Du Dir sparen wenn Du eine eigene Liste(/Array) der relevanten Controls führst.

- Der Thread sollte keine erhöhte Priorität haben, da er durch das Synchronize eh immer wieder ausgebremst wird und auf den Hauptthread wartet. Wenn der Hauptthread nicht dazu kommt Botschaften zu verarbeiten kann Synchronize ewig warten.

- Reagiert der Thread schneller, wenn du mit der Maus auf dem Formular herumeierst? Dann hilft das Umbiegen von WakeMainThread (hatte ich ja schonmal vorgeschlagen).

[EDIT] - Wieviel Zeit verbringt der Thread im Sleep? [/Edit]

Grüsse, Dirk
  Mit Zitat antworten Zitat
hugo1990

Registriert seit: 27. Dez 2006
166 Beiträge
 
Turbo Delphi für Win32
 
#3

Re: warum verlangsamen diese beiden Funktionen meinen Thread

  Alt 25. Sep 2009, 14:14
Hallo,
ich würde mal sagen dein Problem liegt hier:
  Synchronize(UpdateForm3); So wie es aussieht, machst du die ganzen Prüfungen, ob ich etwas an den COM-Ports geändert hat, in der UpdateForm3. Diese Methode lässt du aber mit Synchronize aufrufen, was bewirkt, dass der Thread des Formulars solange angehalten wird, bis die Abarbeitung der UpdateForm3 abgeschlossen ist.
Pack doch diese ganzen Checks in eine andere Methode oder einfach in die Execute Methode und schreib in die UpdateForm3 nur rein, was an der Form3 geändert werden soll. Und dann rufst du die UpdateForm3 mit Synchronize nur dann auf, wenn sich wirklich was geändert hat.
So wie du es gerade implementiert hast, ist der Thread ziemlich nutzlos.

Ich hoffe, dass ich es einiermaßen verständlich erklärt habe.

[edit]
Ok ich habe grad nochmal die Delphihilfe angeschaut und Synchronize bewirkt, dass die Methode im Hauptthread ausgeführt wird und der aktuelle Thread für die Zeit der Ausführung unterbrochen wird. Es kommt im Endeffekt aber auf das selbe raus, dass der Hauptthread während der Abarbeitung der UpdateForm3 nicht auf andere Sachen reagieren kann.
[/edit]
  Mit Zitat antworten Zitat
BAMatze

Registriert seit: 18. Aug 2008
Ort: Berlin
759 Beiträge
 
Turbo Delphi für Win32
 
#4

Re: warum verlangsamen diese beiden Funktionen meinen Thread

  Alt 25. Sep 2009, 14:26
Ok werde ich mal versuchen umzusetzen. Danke euch

[Edit]
Folgende kleine Änderung hat die Schnelligkeit des Threads wieder zu 100% hergestellt (orientiert an dem Lösungsvorschlag von hugo1990):
Delphi-Quellcode:
// bUpdateDataForm1 ist jetzt eine private-Variable des TThreads
procedure TControlCardControlThread.Execute;
var c, iIndex: integer;
begin
  for iIndex := 1 to 5 do (Form3.findcomponent('CheckBox' + inttostr(iIndex+8)) as TCheckBox).Checked:= fabDigChannelSignals[iIndex];
  repeat
  c := GetTickCount;
  bUpdateDataForm1 := ComportSearch(FsLComport); // <-- Zeile aus der UpdateForm3-Procedure entfernt und hier wieder eingefügt
  Synchronize(UpdateForm3);
  c := {interval}50 - (GetTickCount - c);
  if c > 0 then Sleep(c);
until Terminated;
if assigned(FsLComport) then FsLComport.Free;
end;
[/Edit]
2. Account Sero
  Mit Zitat antworten Zitat
Zoot

Registriert seit: 30. Jan 2006
Ort: Hessen
113 Beiträge
 
Delphi 11 Alexandria
 
#5

Re: warum verlangsamen diese beiden Funktionen meinen Thread

  Alt 25. Sep 2009, 15:36
Verstehe aber auch nicht so ganz, warum du dir die vorhandenen Comports in einer Stringliste merkst.
Wäre da nicht ein Statischer Array von der Art Comportaktiv : Array [1..20] of boolean viel einfacher?
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#6

Re: warum verlangsamen diese beiden Funktionen meinen Thread

  Alt 25. Sep 2009, 16:02
Noch eine Anregung, um ein Performanceproblemen bei Verwendung von Synchronize zu umgehen: Verwende Windows-Messages, die das Formular veranlassen, die Threadinformationen neu zu zeichnen.

Dem Thread übergibst du das Handle des Formulars und ruft dann einfach im Thread 'PostMessage(HandleDerForm...)' auf.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  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 02:14 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