![]() |
Liste per Thread abarbeiten
Hallo,
ich bin Anfänger im programmieren von Threads und das lesen von den vielen Themen erzeugt macht einem schnell klar, dass man hier viel falsch machen kann. Deshalb frage ich hier lieber mal nach. Die Aufgabe: Ich habe ein Thread das im Execute-Teil kontinuierlich eine Digitalkarte ausliest.
Delphi-Quellcode:
Parallel soll es aber auch möglich sein, Digitalausgänge zu setzen. Ich hatte hier verschiedene Ansätze
procedure TthrIO.execute;
begin while not Terminated do begin Sleep(50); _MeasureDigIn; end; end; procedure TthrIO._MeasureDigIn; {******************************************************************************* Liest die Anzahl definierter Digitaleingänge ein und stellt Istwerte als Longint-Werte blockweise zur Verfügung _iDigIn[0] = FirstportXX, _iDigIn[1] = SecondportXX, ... *******************************************************************************} var iPort, // Port A, B, CL, CH = 1, 2, 3, 4, ... iULStat : Integer; iValue : TiWerteArr; begin for iPort := 1 to iMaxPort do begin iULStat := cbDIn (iAdr, GetPortType(iPort), iValue[iBlock]); if iULStat > 0 then inc(iFailedDIn); end; _iDigIn := iValue; end; function TthrIO.GetDigIn(iKan:Integer):Boolean; {******************************************************************************* Abruf der Einzelwerte von extern Der Gesamtwert für Kanal 0..23 liegt in _iDigIn[0] 24..47 in _iDigIn[1], usw *******************************************************************************} var iPort : Integer; iVal : Longint; begin Result := false; if succ(iKan)>iDigIn then exit; iPort := trunc(iKan/24); iVal := _iDigIn[iPort]; Result:=odd(iVal shr iKan); end; 1. Der direkte Zugriff auf einzelne Kanäle am Thread vorbei
Delphi-Quellcode:
Wohl nicht die saubere Art bei Threads :oops:
procedure TthrIO.SetDigOut(iKan:Integer; bValue:Boolean);
{******************************************************************************* Setzt je nach Kanal den entsprechenden Port-Wert, der dann im Thread kontinu- ierlich ans Geraet gesendet wird. Dabei wird b erücksichtigt, dass u.U. schon Ports für Digitaleingänge reserviert sind *******************************************************************************} var iULStat : Integer; begin iULStat := cbDBitOut (iAdr, FIRSTPORTA, iKan, Integer(bValue)); if iULStat > 0 then inc(iFailedDOut); end; 2. Karte bietet auch Möglichkeit alle DigOuts mit einem Integer zu setzen. Diesen dann wieder in Execute beschreiben
Delphi-Quellcode:
Nachteil dieser Methode: Ausgänge werden nicht in der Reihenfolge gesetzt, wie es das Programm macht. Im Gegenteil: Da Karte mit 8bit Ports arbeitet, werden Kanäle im 1. Port immer vor denen im 2. gesetzt. Eben auch dann, wenn ich z.B. zuerst Ausgang 9 und dann 4 gesetzt habe.
TthrIO.execute;
begin while not Terminated do begin Sleep(50); _SetDigOut; _MeasureDigIn; end; end; procedure TthrIO._SetDigOut; {******************************************************************************* Setzt die Digitalausgänge blockweise über Excute _iDigOutWerte[0] = FirstportXX, _iDigOutWerte[1] = SecondportXX, ... *******************************************************************************} var iPort, // Port A, B, CL, CH = 1, 2, 3, 4, ... iPortType, iULStat : Integer; begin for iPort := 1 to iMaxPortDigOut do begin // Nur Senden, wenn sich Werte geändert haben if _iDigOutWerte[Pred(iPort)] <> iDigOutWerte[Pred(iPort)] then begin iPortType := GetPortType(iMaxPortDigIn + iPort); iULStat := cbDOut (iAdr, iPortType, iDigOutWerte[iPort-1]); if iULStat <> 0 then inc(iFailedDOut) else _iDigOutWerte[Pred(iPort)] := iDigOutWerte[Pred(iPort)]; end; end; end; procedure TthrIO.SetDigOut(iKan:Integer; bValue:Boolean); {******************************************************************************* Setzt je nach Kanal den entsprechenden Port-Wert, der dann im Thread kontinu- ierlich ans Geraet gesendet wird. Dabei wird b erücksichtigt, dass u.U. schon Ports für Digitaleingänge reserviert sind *******************************************************************************} var iPort, iPortType, iULStat, iKorr : Integer; begin iKan := iKan + iDigIn; iPort := pred(GetPort(iKan)); iKorr := iKan - GetShl(iPort+1) - (iKan div 24) * 24; iPort := iPort - iMaxPortDigIn; if bValue then iDigOutWerte[iPort] := iDigOutWerte[iPort] or (1 shl iKorr) else iDigOutWerte[iPort] := iDigOutWerte[iPort] and (not (1 shl iKorr)); end 3. Möglichkeit: Ich hänge neue Werte in einer Liste immer hinten an und der Thread arbeitet diese wieder von oben nach unten ab und lösche erfolgreich gesetzte Ausgänge in der Liste wieder.
Delphi-Quellcode:
Hier beginnt aber meine Unsicherheit, ob das was ich hier mach auch Threadsicher ist bzw. was ich machen muss, damit es es wird.
TValDigOut = record
Kan : integer; Value : Boolean; end; TArrValDigOut = Array of TValDigOut; procedure TthrIO._SetDigOut; {******************************************************************************* Setzt jeden Digitalausgang der Reihe nach wie sie gesetzt wurden *******************************************************************************} var iULStat : Integer; procedure DeleteArrayIndex(var X: TArrValDigOut; Index: Integer); begin Finalize(X[Index]); System.Move(X[succ(Index)], X[Index], (high(X) - Index) * succ(SizeOf(TValDigOut))); SetLength(X, high(X)); end; begin while high(DigOutWerte) > 0 do begin iULStat := cbDBitOut (iAdr, FIRSTPORTA, DigOutWerte[0].Kan, Integer(DigOutWerte[0].Value)); if iULStat <> 0 then inc(iFailedDOut) else DeleteArrayIndex(DigOutWerte, 0); end; end; procedure TthrIO.SetDigOut(iKan:Integer; bValue:Boolean); {******************************************************************************* Schreibt den zu setzenden Kanal in eine Liste die dann _SetDigOut abarbeitet *******************************************************************************} begin SetLength(DigOutWerte, succ(length(DigOutWerte))); with DigOutWerte[high(DigOutWerte)] do begin Kan := iKan; Value := bValue; end; end; Viele Grüße Gerd |
AW: Liste per Thread abarbeiten
Wenn die Karte das unabhängige Lesen und Schreiben erlaubt, dann spricht nichts gegen Möglichkeit #1.
Die beiden anderen Möglichkeiten sind aber auch interessant, aber nur dann einzusetzen, wenn es sinnvoll ist. Das wäre dann der Fall, wenn Du viele Consumer der 'SetDigOut' hast, die sich auf die Füße treten könnten. Dann wäre eben #2 oder #2 sinnvoller. Welche von den Möglichkeiten Du verwenden willst, bleibt Dir überlassen. Beide haben Vor- und Nachteile die Du aber selbst einschätzen musst, denn ich kenne die Eigenschaften der Karte nicht. |
AW: Liste per Thread abarbeiten
Wenn es wichtig ist, in welcher Reihenfolge die Ausgänge gesetzt werden, dann ist ein Blick auf die TQueue-Klasse einen Blick wert. In diese Queue "schiebt" man sozusagen seine Schaltanweisung hinein und der Thread nimmt sie in derselben Reihenfolge auch wieder heraus (FIFO-Prinzip). Synchronisieren kann man das mit CriticalSections oder Events, je nach Geschmack.
Spielt die Reihenfolge keine Rolle, dann Option #2. |
AW: Liste per Thread abarbeiten
Hallo zusammen,
Ich habe heute gemerkt, dass die Probleme die ich hatte, zwei verschiedene Ursachen hatten:
Danke für euer Feedback Gerd |
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:24 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