![]() |
Re: Thread - Synchronize - 2 Forms - Verständnisproblem
Vielen Dank an alle.
Das mit der Trennung von Anzeige und Daten ist so eine Sache, da die Anzeige ja die Daten anzeigt :gruebel: Bedeutet, ich interagiere ja in dem Moment, wo ich die Daten lade, ja schon mit der Anzeige, da das VCL-Objekt ja die Daten lädt. |
Re: Thread - Synchronize - 2 Forms - Verständnisproblem
Ich nochmal.
Zitat:
|
Re: Thread - Synchronize - 2 Forms - Verständnisproblem
@wicht,
das klingt einleuchtend! Werde das mal probieren umzusetzen. Danke nochmal an alle! |
Re: Thread - Synchronize - 2 Forms - Verständnisproblem
Hallo,
darf ich auch mal eine Frage bezüglich Threads stellen? Bis dato hatte ich noch keine Threads für meine Anwendungen benötigt, bei meinem jetzigen Projekt (Lichtsteuerung) sollten/müssen mehrere dinge selbstständig laufen. Mein Problem ist das ich zur Laufzeit mehrere Frames erzeuge je nach Anzahl der Scheinwerfer. Nun versuche ich in den Frames einen Thread zu integrieren damit diese Frames selbstständig ihr Werte für die visuelle Darstellung erzeugen. Die Daten dafür sollen sie sich aus dem Hauptform aus einem record hohlen. Geht das überhaupt da die threads ja mit den Frames zu Laufzeit erzeugt werden. MfG Dirk |
Re: Thread - Synchronize - 2 Forms - Verständnisproblem
Funktionalität und Darstellung sollten in einem Programm sowieso getrennt sein.
Bei Threads ist das Pflicht. Ein Beispiel wie man das in diesem Fall angehen könnte: Definiere eine eigene Nachricht: WM_STATUS = WM_USER + xxxx; Aufgabe des Hauptthreads: Vergieb für jede Aufgabe eine Nummer/ID. Erzeuge entsprechende Threads und übergib diesen ihre Aufgaben und das Handle eines Fensters (das über Statusänderungen informieren soll). Erzeuge entsprechende Frames für jede zu visualisierende Aufgabe. Aufgabe des Subthreads: Führe deine Aufgabe aus. Ändert sich der Status, informiere das angegebene Fenster: PostMessage(WindowHandle, WM_STATUS, ID, 0); Aufgabe des Hauptthreads: Wenn eine Nachricht von über eine Statusänderung eintrifft, finde auf Grund der ID das entsprechende Frame und rufe die Methode zur Aktualisierung der Darstellung auf. Statt Nachrichten könnte man auch Synchronize verwenden, das bremst aber die Subthreads aus. |
Re: Thread - Synchronize - 2 Forms - Verständnisproblem
Hallo
Danke werde mich mal mit der sache beschäftigen, habe ich noch nicht gemacht. MfG |
Re: Thread - Synchronize - 2 Forms - Verständnisproblem
Hallo,
mit dem ganzen Threating steige ich nicht so richtig hinter. Jetzt habe ich gnadenlos drauf losprogrammiert ohne Rücksicht auf Verluste. Neben dem Hauptprogramm habe ich mir einen Thread erstellt (ShowThread = class(TThread) mit dem ich meine Ablaufsteuerung realisiert habe. In der Ablaufsteuerung greift der Thread direkt auf einen Record (array) zu wo er sich Daten für seine Aufgabe holt und seine Ergebnisse auch wieder ablegt. Die Daten für die VLC Komponenten mache ich über Synchronize denke das ist ok. Auf die Felder auf die er seine Ergebnisse ablegt, schreibt auch kein anderer Thread Daten rein also nur ein Ausgabepuffer. Jetzt benötige ich noch einen Thread (OutputThread) der aus den Ergebnissen des Thread (ShowThread) die eigentlichen Ausgangsdaten erzeugt, muss ich da auf etwas achten (kritischer Abschnitt oder so) wenn die Daten von anderen Threads nur gelesen werden oder kann es zu Konflikten kommen? MfG Dirk |
Re: Thread - Synchronize - 2 Forms - Verständnisproblem
Sobald ein Thread in einen bestimmten Speicherbereich schreibt, ist ein "kritischer Abschnitt" erforderlich, wenn andere Threads ebenfalls lesend oder schreibend auf diesen Speicherbereich zugreifen sollen.
|
Re: Thread - Synchronize - 2 Forms - Verständnisproblem
Hallo an alle,
ich bin wahrscheinlich zu bl..... :wall: Ich steige da nich hinter, habe zwar ein wenig gelesen aber das was ich will ist nirgens nur ansatzweise zu finden. Habe mir mal erlaub ein Stück Quellcode reinzusetzen.
Delphi-Quellcode:
Es funktioniert zwar alles störungsfrei aber ich denke das es nicht richtig ist, wäre sonst zu
unit ShowThreadPars;
interface uses Windows, Messages, Classes, SysUtils, Forms, Variants, Graphics, Controls, Dialogs, StdCtrls, ExtCtrls, ComCtrls, ToolWin, ParFrame; type ShowThread = class(TThread) procedure SetData(Value:Byte); procedure ParsOut; function SetColor(Value:Byte; index:Byte): TColor; protected procedure Execute; override; end; Var tParsindex : Byte; // Rückgabewert tTrackbarValue : Byte; // Rückgabewert tLabelValue : String; // Rückgabewert tShapeColor : Tcolor; // Rückgabewert tShapeValue : Byte; tDmxAdr : Byte; tDMXValue: Byte; tFrames : Integer; tProgRunOld : array [1..32] of Byte; tProgRunTemp : array [1..2,1..32] of Byte; tProgStepTemp : Byte = 1 ; implementation uses ProLightControlForm; // ----------------------------------------------------------------------------- procedure ShowThread.Execute; Var I : Byte; begin // stopen des thread durch hauptprogramm while fThreadParExit do begin ------------------------------------------------------------------------------------- 'PARMAX' ist eine Variabel aus dem Hauptprogramm die sich aber jederzeit ändern kann auch wärend der Tread läuft ------------------------------------------------------------------------------------- // hauptschleife für alle parser For i:= 1 to ParMax do begin . . . ------------------------------------------------------------------------------- HIER GREIFE ICH AUF VARIABLE IM HAUPTTREAD ZU UM SIE ZU LESEN BZW. ZU SCHREIBEN ------------------------------------------------------------------------------- tDmxAdr := ParCount[i,1]; // dmx adresse des pars hohlen if fStandbyActive then begin Device[tDmxAdr].DMXP := ProgRun[ProgStep,i]; // daten in ausgabe-array zurückschreiben tProgRunOld[i] := ProgRun[ProgStep,i]; // hilfsarray für flash funktion... end else begin Device[tDmxAdr].DMXP := tProgRunOld[i];// daten aktuell halten end; . . . --------------------------------------- HIER SCHREIBEN ICH DIREKT IN DEN RECORD --------------------------------------- if Device[tDmxAdr].ParStatus = 1 Then Device[tDmxAdr].DMXP := 255; SetData(tDmxAdr); // ausgabedaten berechnen . . . ----------------------------- AKTUALISIEREN DER VCL OBJEKTE ----------------------------- if tProgRunTemp[1,tDmxAdr] <> tProgRunTemp[2,tDmxAdr] then // Ausgabe visualisierung Synchronize(ParsOut); tProgRunTemp[2,tDmxAdr]:=tProgRunTemp[1,tDmxAdr]; sleep(1); end; // end For next end; end; // ----------------------------------------------------------------------------- // end For next end; end; // ----------------------------------------------------------------------------- procedure ShowThread.ParsOut; Begin ProLightForm.Thread_Parasync(tParsindex, tTrackbarValue,tLabelValue, tShapeColor) end; // ----------------------------------------------------------------------------- procedure ShowThread.SetData(Value:Byte); Var dmxValueStr : String; begin tShapeValue := Device[tDmxAdr].ParColorSet; // Colorindex holen tDMXValue := Device[tDmxAdr].ParDmxOut; // Programmwert holen tProgRunTemp[1,tDmxAdr]:=tDMXValue; // nach speedfader . . . . einfach. Kann mir da mal jemand helfen, wie ich einen sauberen Zugriff auf Variable im Haupttread hinbekomme da die sich ständig ändernden Daten und der Tread darauf reagieren soll. MfG Dirk |
Re: Thread - Synchronize - 2 Forms - Verständnisproblem
Delphi-Quellcode:
Diese ganzen globalen Variablen gehn überhaupt nicht. Eine Variable sollte immer jemanden gehören.
Var
tParsindex : Byte; // Rückgabewert tTrackbarValue : Byte; // Rückgabewert tLabelValue : String; // Rückgabewert tShapeColor : Tcolor; // Rückgabewert tShapeValue : Byte; tDmxAdr : Byte; tDMXValue: Byte; tFrames : Integer; tProgRunOld : array [1..32] of Byte; tProgRunTemp : array [1..2,1..32] of Byte; tProgStepTemp : Byte = 1 ; implementation In diesem Fall entweder einem Formular oder dem Thread und jeweils dort in den private oder protected-Abschnitt deklariert. Andere Klassen können grundsätzlich nur über property auf diese Variablen zugreifen. -----------------------------------------------------------------------------
Delphi-Quellcode:
Das gehört so nicht in eine Unit, die sich um die Funktionalität kümmert (Trennung von Funktionaliät und Oberfläche).
uses ProLightControlForm;
{...} Synchronize(ParsOut); {...} procedure ShowThread.ParsOut; Begin ProLightForm.Thread_Parasync(tParsindex, tTrackbarValue,tLabelValue, tShapeColor) end; Man kann zwei Fälle unterscheiden: 1. das Ereignis muss sofort bearbeitet und der Thread in der Zwischenzeit anhalten 2. das Ereignis kann bei nächster Gelegenheit verarbeitet werden, der Thread kann weiter arbeiten Fall 1.: In diesem Fall ist Synchronize() erforderlich. Die Methode sollte aber nicht direkt, sondern über einen Methodenzeiger(oder Interface) erfolgen.
Delphi-Quellcode:
Fall 2.:
TParasyncMethode = procedure(Sender: TObject {optional weitere Parameter}) of object;
ShowThread = class(TThread) {...} private FOnParasync: TParasyncMethode; procedure SetOnPararasync(AValue: TParasyncMethode); function GetOnPararasync: TParasyncMethode; public property OnParasync: TParasyncMethode read GetOnPararasync write SetOnPararasync; {...} procedure ShowThread.ParsOut; var lParasync: TParasyncMethode; Begin lParasync := GetOnPararasync; if Assigned(lParasync) then lParasync(Self {optional weitere Parameter}); end; Synchronize() ist nicht erforderlich. Der Hauptthread wird asynchron mit Hilfe von Nachrichten informiert. Man kann ein eigenes threadsicheres Nachrichtensystem implementieren oder man nutzt das von Windows.
Delphi-Quellcode:
-----------------------------------------------------------------------------
const
WM_Parasync = WM_User + XXX; ShowThread = class(TThread) {...} private FParasyncWnd: THandle; procedure SetPararasyncWnd(AValue: THandle); function GetPararasyncWnd: THandle; public property ParasyncWnd: THandleread GetPararasyncWnr write SetPararasyncWnd; {...} procedure ShowThread.ParsOut; var lParasyncWnd: THandle; Begin lParasyncWnd := GetParasyncWnd; if Assigned(lParasyncWnd) then PostMessage(lParasyncWnd, WM_Parasync, Integer(Pointer(Self)), 0 {Optional weiterer Parameter}); end; Threadsicherer Zugriff auf interne Variabeln eines Objekts über Getter und Setter:
Delphi-Quellcode:
Auf die interne Variable FPararasyncWnd darf in diesem Fall nirgends sonst zugegriffen werden,
private
FSection: TCriticelSection; {im Konstruktor erzeigen, im Destrucor freigeben, in der Regel wird nur eine je Objekt benötigt} {...} procedure ShowThread.SetPararasyncWnd(AValue: THandle); begin FSection.Acquire; try FPararasyncWnd := AValue; finally FSection.Release; end; end; function ShowThread.GetPararasyncWnd: THandle; begin FSection.Acquire; try Result := FPararasyncWnd; finally FSection.Release; end; end; einzige Ausnahme in einem genauso mit FSection abgesicherten Abschnitt. Der selbe Mechanismus müsste auch in alle anderen Klassen eingebaut werden, auf dessen Property der Thread zugreifen soll. Das würde ich aber vermeiden, neue Daten sollten immer vom Hauptthread and den Subtrhead übergeben oder von dort abgeholt werden. Der letzte Satz sollte eigentlich deine Frage beantworten, übergib geänderte Daten an eine so absicherte Methode. Der Thread erstellt sich eine Kopie davon und arbeitet mit dieser. Schreibfehler wurden eingefügt, um die Aufmerksamkeit des Lesers zu erhöhen. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 19:53 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