Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   2 Threads mit Events synchonisiern (https://www.delphipraxis.net/52892-2-threads-mit-events-synchonisiern.html)

Osse 6. Sep 2005 10:35


2 Threads mit Events synchonisiern
 
Moin Leute,

wahrscheinlich steht das hier schon mal irgendwo im Thread und ich bin nur zu dämlich die richtigen Suchbegriffe einzugeben.
Hab mir schon das super Thread Tutorial von Luckie angeschaut und ne menge gelernt.
Doch leider hängt es bei mir an einer Kleinigkeit, die für mich unüberwindbar ist. :wall:

Mein Programm besteht aus 2 Threads. Der eine guckt die ganze Zeit an dem USB Port, ob Daten ankommen. Der zweite ist für die Visualisierung verantwortlich.

Mein Problem ist diese beiden Threads interagieren zu lassen. Zu diesem Zweck möchte ich Events verwenden. Wenn die Daten ankommen werden diese von dem 2. Thread zwischengespeichert und gefiltert. Anschließend wird der 1. Thread aufgerufen der diese Daten anzeigt. Ich glaube, dass ich falsch auf die Events zugreife, da meine Prozessorauslastung auf 40% steigt.

Ich greife in dem 2. Thread auf das Event des 1. Threads zu.

Delphi-Quellcode:
dwResult := WaitForSingleObject(Form1.FRcvEvent.Handle, INFINITE);
Damit, bin ich ja nicht mehr unabhängig, und die Prozesse laufen ja nicht mehr parallel. Soweit mir das mein Verstand sagt und ich das Tutorial richitg verstanden habe.

Würde gerne wissen, wie und wo ich das Event iniatlisiern muss. Ich muss ja irgendwie einen Bezug zwischen den einzelnen Threads herstellen. Hoffentlich hat mich irgendjemand verstanden. :roll:

Ich möchte ein Event initalisieren, welches von dem 1. Thread ausgelöst wird und vom 2. ausgelesen. Brauch ich da einen dritten thread, wo die die Events verwaltet werden??

Beispiele wären sehr hilfreich, Danke

Oliver

chaosben 6. Sep 2005 11:08

Re: 2 Threads mit Events synchonisiern
 
Tja, ich hätte da ein globale Variable im Angebot, die von dem "aufrufenden" Thread gesetzt wird und vom getriggerten Thread gelesen wird.

Osse 6. Sep 2005 12:01

Re: 2 Threads mit Events synchonisiern
 
Ja, gut und schön, das ist ja genau das was ich gemacht habe.

Ich generiere das Event in dem 1. Thread, wo es auch ausgelesen wird. Dieses Event übergebe ich und löse es von dem 2. Thread aus.

Meinst du, ich soll das Event nicht immer aus dem anderen Thread abfragen, sondern dieses in einer Variablen im 2. Thread übergeben. Diesen übergebenen Parameter dann benutzen???

messie 6. Sep 2005 12:08

Re: 2 Threads mit Events synchonisiern
 
Sachmal,

das hatten wir doch schonmal? Hat Dir die Antwort nicht gereicht oder hast Du sie nach Deinem Diplomarbeit-Reset :cheers: vergessen?

Grüße, Messie

Osse 6. Sep 2005 12:34

Re: 2 Threads mit Events synchonisiern
 
Jo, so ähnlich hatten wir das schonmal.

Hab mal wieder in mein Projekt nach einer sehr langen und schönen :cheers: Phase reingeschaut. Dabei ist mir aufgefallen, dass mein Prozessor (immerhin 1,6Ghz Laptop) teilweise ne Prozessorauslastung von 40% hat und da dachte ich mir, dass ich dem mal nachgehe (was soll man sonst machen, :dancer: ??).

Dabei ist mir eben aufgefallen, dass ich immer lustig :bounce1: von dem einen Thread die Variablen aus dem anderen Abfrage. Dadurch ,denke ich mir zumindest :gruebel: , dass ich dadurch diese hohe Systemauslastung habe.

Habe nicht mit Critical Sections gearbeitet sondern mit der Synchronizise Methode und es hat auch ganz gut funktioniert. Dachte mir das ganze nochmal mit Critical Sections. und Events zu basteln.

Jetzt stellt sich nur die Frage, wo diese initalisiert werden und wie díe Daten übergeben werden. Logischerweise gibt es die Klasse mit Critical Sections. In dieser stehen alle Parameter drin, welche von beiden Threads benutzt werden. Soweit so gut, aber wo und wie wird diese Initalisiert. Der Thread 1 muss ja wissen, dass Thread 2 das auch mitbenutzt.

Muss ich wirklich aus Thread2 dann Thread1.CriticalSection.Variable die werte auslesen???

messie 6. Sep 2005 12:55

Re: 2 Threads mit Events synchonisiern
 
Mit critical sections habe ich noch nicht gearbeitet und mit events bin ich auch eher unerfahren. Aber Deine Prozessorauslastung von 40% kommt mit ziemlich normal vor. Du hattest einen Thread, der Daten irgendwo abgeholt hat und einen, der die verarbeitet hat. Wenn Du die Threads nicht gelegentlich mal supendest (riskant) oder mit sleep oder waitforsingleobject lahmlegst, bleibt unabhängig von der Priorität immer eine Prozessorauslastung von 100%.

Grüße, Messie

Osse 6. Sep 2005 13:03

Re: 2 Threads mit Events synchonisiern
 
Ich bekomme die ankommenden Daten durch ein Event signalisiert und reagiere dann. Problem ist, dass ich auch den Werte-Austausch zwischen den Threads habe. Ich stehe aber immer noch vor dem Problem der initalisierung :wall: .

shmia 6. Sep 2005 13:26

Re: 2 Threads mit Events synchonisiern
 
Critical Sections wären das falsche Werkzeug.
Du benötigst Events.

1.) du erstellt ein Objekt der Klasse TEvent auf dem Hauptformular (oder sonstwie global)
Diese Objekt "lebt" also länger als die beiden Threads
Delphi-Quellcode:
   FEvent := TEvent.Create(nil, True, False, 'MeinEvent5641');
2.) Dein 1. Thread setzt das Event, wenn Daten vorhanden
Delphi-Quellcode:
   ...Event.SetEvent;
3.) Dein visualisierung Thread wartet auf das Event:
Delphi-Quellcode:
procedure TVisThread.Execute
var
   wr : TWaitResult;
begin
   while not Terminated do
   begin
     // immer nur max. 2 sek warten, damit der Thread nicht ewig hängt
     wr := ...Event.Waitfor(2000);
     if wr = wrSignaled then
     begin
        ...Event.ResetEvent;
        // hier Daten entgegennehmen und anzeigen
     end;
   end;
end;

Osse 6. Sep 2005 16:25

Re: 2 Threads mit Events synchonisiern
 
Danke shima,

das ist schon mal sehr gut, doch leider hängt das ganze bei mir, denn:

Mein Hauptformular ist mein Hauptthread (Thread 1)in dem die Anzeige gemacht wird. Das Heißt ich müsste doch eine Funktion schreiben, die dann ausgeführt wird, so wie bei einem Interrupt (komme aus der uC Welt). Also eine Procedure für das Event, so wie Button on Klick. Nur wie lautet der Funktionsaufruf, hab in den Methoden nix gefunden :wall: .

Der 2. Thread guckt die ganze Zeit nach den Eingangsdaten.

Die Lösung ist also nicht verwendbar.

Delphi-Quellcode:
procedure TVisThread.Execute
var
   wr : TWaitResult;
begin
   while not Terminated do
   begin
     // immer nur max. 2 sek warten, damit der Thread nicht ewig hängt
     wr := ...Event.Waitfor(2000);
     if wr = wrSignaled then
     begin
        ...Event.ResetEvent;
        // hier Daten entgegennehmen und anzeigen
     end;
   end;
end;
Muss ich zwingend einen weiteren Thread haben um diesen Code auszuführen, oder gibt es die oben von mir angedachte Lösung??

Hab da noch ne Frage zu den Events:

Zitat:

constructor Create(EventAttributes: PSecurityAttributes; ManualReset, InitialState: Boolean; const Name: string);

HAb mal nachgelesen, das mit dem PSecurityAttributes ein vorhandenes Eventgeöffnet werden kann (Delphi 5 hilfe). Das ist ja genau das was ich brauche, oder??
Noch eine letzte Frage zu dem Namen: Damit ist das Event eindeutig identifizierbar, oder??

Wieso schreibst du immer ...Event das muss doch immer gleich heißen oder? Wenn du es mit FEvent angelegt hast, dann muss es auch FEvent bleiben, oder und kann nicht ich-mach-was-ich-will-Event werden?? :gruebel:

messie 6. Sep 2005 16:44

Re: 2 Threads mit Events synchonisiern
 
Zitat:

Mein Hauptformular ist mein Hauptthread (Thread 1)in dem die Anzeige gemacht wird.
Igitt!
Das wird immer Probleme geben, weil der Hauptthread des Programmfensters die Kommunikation mit den Windows-Events betreibt - Du hast halt nicht die volle Kontrolle darüber. Gerade für zeitkritische Sachen wie die Datenübergabe völlig ungeeignet.
Wenn ich etwas synchronisiere mache ich immer einen eigenen Thread draus, der das Programmfenster mir Daten füttert.

Grüße, Messie

shmia 6. Sep 2005 16:59

Re: 2 Threads mit Events synchonisiern
 
Zitat:

Zitat von Osse
Mein Hauptformular ist mein Hauptthread (Thread 1)in dem die Anzeige gemacht wird. Das Heißt ich müsste doch eine Funktion schreiben, die dann ausgeführt wird, so wie bei einem Interrupt (komme aus der uC Welt). Also eine Procedure für das Event, so wie Button on Klick. Nur wie lautet der Funktionsaufruf, hab in den Methoden nix gefunden :wall: .

Der 2. Thread guckt die ganze Zeit nach den Eingangsdaten.

Achso, du nimmst den Hauptthread, um die Daten anzuzeigen.
Dann gäbe es da auch eine ganz einfache Möglichkeit.
Dein Daten-Sammel Thread posted einfach eine benutzerdefinierte Message:
Delphi-Quellcode:
const UM_DATA_UPDATE = WM_USER +1; // benutzerdefinierte Message

// Thread
if neue_daten_da then
   // Message wird in die windowsMessage Queue gelegt; der Thread rennt ungebremst weiter
   PostMessage(Application.Mainform.Handle, UM_DATA_UPDATE, 0,0);

// im Hauptformular
    procedure DATA_UPDATE(var msg: TMessage); message UM_DATA_UPDATE;
// in obiger Prozedure werden dann die Daten abgeholt und evtl. auch visualisiert
Zitat:

Zitat von Osse
Wieso schreibst du immer ...Event das muss doch immer gleich heißen oder? Wenn du es mit FEvent angelegt hast, dann muss es auch FEvent bleiben, oder und kann nicht ich-mach-was-ich-will-Event werden??

Weil FEvent entweder eine globale Variable oder eine Variable eines Formulars ist.
Wenn ich von einem Thread auf eine Variable eines Formulars zugreife, sieht das so aus:
Delphi-Quellcode:
  AnzeigeForm.Event.SetEvent;
// bei Zugriff auf eine globale Variable entfällt natürlich AnzeigeForm.

chaosben 7. Sep 2005 05:33

Re: 2 Threads mit Events synchonisiern
 
Auch auf die Gefahr hin, das ich an euch allen vorbei-rede, weil ich nicht richtig "zugelesen" (aka zugehört :)) habe versuch ichs noch mal. Mein Lösungsvorschlag ist der folgende:

Delphi-Quellcode:
TDataThread = class(TThread)
... bla blubber
end;

TVisualThread = class(TThread)
... didel dadel
end;

var
  DataAvailable : Boolean;
  Data : IchKennDenTypNicht;
  thrData : TDataThread;
  thrViusal : TVisualThread;

procedure TDataThread.Execute();
var
  TempData : VonObigemTyp;
begin
  while not suspended ot terminated do
  begin
    TempData:=WoGibtsDennHierDieDaten();
    //Hier drum kümmern das "Data" solange nicht überschrieben wird, solange der andere Thread die nicht gelese n hat
    //danach:
      DataAvailable:=true;
    sleep(2); //Oder natürlich WaitForSingleObject oder ähnlich; aber mindestens eine 1ms schlafen, sonst (b)rennt die CPU
  end;
end;

procedure TVisualThread.Execute();
begin
  while not Suspended or Terminated do
  begin
    if (DataAvailable) then
    begin
       Synchronize(MachWasMitDenDaten);
       DataAvailable:=false;
    end;
    sleep(2); //Der "armen" CPU zuliebe :)
  end;
end;

procedure TForm1.Create(Sender:TObject);
begin
  DataAvailable:=false;
  thrData:=TDataThread.Create ...
  thrVisual:=TVisualThread.Create ...
end;


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:32 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