Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Algorithmen, Datenstrukturen und Klassendesign (https://www.delphipraxis.net/78-algorithmen-datenstrukturen-und-klassendesign/)
-   -   Datenaustausch zwischen Threads (Sync) (https://www.delphipraxis.net/163295-datenaustausch-zwischen-threads-sync.html)

fuchsle 23. Sep 2011 14:45

Datenaustausch zwischen Threads (Sync)
 
Hallo zusammen,

ich habe die Suchfunktion nun schon länger geplagt und schon einige Beispiele durch. Leider hat es mir noch immer nicht auf die Sprünge geholfen.

Bei ist ein Thread zuständig Daten zu sammel, der Andere soll Diese per TCP/IP bereitstellen.
Beide Threads arbeiten wie erwartet, aber sobald ich die gesammelten Daten (4 double) in die property des anderen thread schreiben möchte bekomm ich eine Fehlermeldung:

Zugriffsverletzung ... Schreiben von Adresse ...

Delphi-Quellcode:

      Synchronize(ExtUpdate);

// ...

procedure ThreadValue.ExtUpdate;
begin
  TCPIP.TCP_NO2_10 := NO2_10;
  TCPIP.TCP_NO2_06 := NO2_06;
  TCPIP.TCP_CompAir := CompAir;
  TCPIP.TCP_Coolant := Coolant;
end;
Bisher bin ich davon ausgegangen, dass ich mit einem Synchronize() es schaffe auf den anderen Thread zu zu greifen.


Ich bin über eure Hilfe dankbar,
leider noch Anfänger, was Delphi betrifft und OOP, daher evtl. auch auf dem Holzweg :(

CCRDude 23. Sep 2011 15:13

AW: Datenaustausch zwischen Threads (Sync)
 
Schau Dir mal TMultiReadExclusiveWriteSynchronizer an :)

BUG 23. Sep 2011 18:34

AW: Datenaustausch zwischen Threads (Sync)
 
Zitat:

Zitat von fuchsle (Beitrag 1126237)
Bisher bin ich davon ausgegangen, dass ich mit einem Synchronize() es schaffe auf den anderen Thread zu zu greifen.

Synchronize() bringt dich in den Kontext des Hauptthreads, dein anderer Thread ist davon nicht betroffen.

Sir Rufo 23. Sep 2011 18:41

AW: Datenaustausch zwischen Threads (Sync)
 
Es gibt von Synchronize aber auch noch ein paar überladene Methoden, wo man den gewünschten Thread-Kontext angeben kann.

Ansonsten mit Critical Sections arbeiten, wenn die Daten einfach nur abgeliefert werden sollen.

Und anstatt Synchronize kann man es auch mal mit Queue versuchen :)

BUG 23. Sep 2011 20:44

AW: Datenaustausch zwischen Threads (Sync)
 
Zitat:

Zitat von Sir Rufo (Beitrag 1126309)
Es gibt von Synchronize aber auch noch ein paar überladene Methoden, wo man den gewünschten Thread-Kontext angeben kann.

Leicht OT: wie soll das funktionieren?
Beim MainThread ist es ja leicht vorstellbar, da der quasi Ereignisgesteuert ist.
Aber in Execute kann ich doch machen was ich will, wie soll man da ein synchronisiertes Event hereinschmuggeln?

EDIT: Oder meinst du die statischen Methoden:
http://docwiki.embarcadero.com/VCL/en/Classes.TThread.Synchronize
The current thread is passed in the AThread parameter.

Sir Rufo 23. Sep 2011 23:40

AW: Datenaustausch zwischen Threads (Sync)
 
U are right :) das mit dem Sync kann man da vergessen.

Somit verbleibt als Lösung eine Queue zwischen die beiden Threads zu legen, die von dem einen befüllt und dem anderen abgearbeitet wird.
Das Befüllen und Auslesen muss zwingend mit einer CriticalSection abgesichert werden, oder alternativ mit dem MultiRead-Onkel ;)
Da es sich aber nur um einen Thread handelt wird das keine Vorteile ergeben, aber auch keine Nachteile.

chaosben 24. Sep 2011 06:36

AW: Datenaustausch zwischen Threads (Sync)
 
Zitat:

Zitat von CCRDude (Beitrag 1126248)
Schau Dir mal TMultiReadExclusiveWriteSynchronizer an :)

Als Alternative gibts dann nach die TCriticalSection aus der Unit SyncObjs

mjustin 24. Sep 2011 09:03

AW: Datenaustausch zwischen Threads (Sync)
 
Zitat:

Zitat von chaosben (Beitrag 1126360)
Zitat:

Zitat von CCRDude (Beitrag 1126248)
Schau Dir mal TMultiReadExclusiveWriteSynchronizer an :)

Als Alternative gibts dann nach die TCriticalSection aus der Unit SyncObjs


Und dann ist da noch System.TMonitor (für das eigens TObject erweitert wurde).

Sir Rufo 24. Sep 2011 09:05

AW: Datenaustausch zwischen Threads (Sync)
 
Zitat:

Zitat von chaosben (Beitrag 1126360)
Zitat:

Zitat von CCRDude (Beitrag 1126248)
Schau Dir mal TMultiReadExclusiveWriteSynchronizer an :)

Als Alternative gibts dann nach die TCriticalSection aus der Unit SyncObjs

Eine TCriticalSection sperrt aber immer komplett beim Lesen und Schreiben (Enter..Leave), der TMultiReadExclusiveWriteSynchronizer sperrt aber immer nur bei Schreibzugriffen (BeginWrite..EndWrite).
Somit sind die schon mal A sehr verwandt und B in einer MultiThread-Umgebung besser.

Allerdings in dieser vom TE aufgezeigten Konstellation nicht notwendig (2 Threads schreibend, 1 Thread lesend) ;)
Der Aufwand die beiden zu implementieren bleibt aber gleich, somit würde ich dem TMultiReadExclusiveWriteSynchronizer wohl doch den Vorzug geben :)

himitsu 24. Sep 2011 09:20

AW: Datenaustausch zwischen Threads (Sync)
 
Zitat:

Zitat von Sir Rufo (Beitrag 1126379)
Eine TCriticalSection sperrt aber immer komplett beim Lesen und Schreiben (Enter..Leave), der TMultiReadExclusiveWriteSynchronizer sperrt aber immer nur bei Schreibzugriffen (BeginWrite..EndWrite).
Somit sind die schon mal A sehr verwandt und B in einer MultiThread-Umgebung besser.

Wenn sich aber beim Lesen etwas verändert, dann zählt das als Schreibzugriff und muß ebenfalls gesperrt werden.
z.B. das Auslesen eines Streams, wo sich ja der Positionszeiger ändert.

chaosben 24. Sep 2011 11:26

AW: Datenaustausch zwischen Threads (Sync)
 
[QUOTE=Sir Rufo;1126379]
Zitat:

Zitat von chaosben (Beitrag 1126360)
Der Aufwand die beiden zu implementieren bleibt aber gleich, somit würde ich dem TMultiReadExclusiveWriteSynchronizer wohl doch den Vorzug geben :)

Seit ich weiß, wie langsam der TMREWS ist, mag ich ihn nicht mehr. :)
Oder anders gesagt: Wenn man keine rekursiven Aufrufe oder Elevation braucht, ist SlimReadWriteLock die viel schnellere Variante.

fuchsle 29. Sep 2011 13:35

AW: Datenaustausch zwischen Threads (Sync)
 
Hallo,

vielen Dank für eure Antworten, durch eine Erkältung komm ich erst jetzt wieder zur Sache.

Habe mich nun was die kritischen Bereiche betrifft versucht kundig zu machen.
Mit einem kritischen Bereich schütze ich Speicherbereiche.
Wenn ich nun eine Property damit schützen möchte, so muss ich die Methode für den kritischen Bereich in die Lese- und in die Schreibmethode der Property packen?

Delphi-Quellcode:
function ThreadValue.getNO2_10: Double;
begin
  try
    CSNO2_10.Acquire; // lock out other threads
    Result := FNO2_10;
  finally
    CSNO2_10.Release;
  end;
end;
Delphi-Quellcode:
procedure ThreadValue.setNO2_10(const Value: Double);
begin
  try
    CSNO2_10.Acquire; // lock out other threads
    FNO2_10 := Value;
  finally
    CSNO2_10.Release;
  end;
end;

So habe ich die Kritischen Bereiche definiert:

Delphi-Quellcode:
type
  ThreadValue = class(TThread)

  private
    { Private-Deklarationen }

    CSNO2_10: TCriticalSection;
    CSNO2_06: TCriticalSection;
    CSCompAir: TCriticalSection;
    CSCoolant: TCriticalSection;
Delphi-Quellcode:
{ ThreadGetValue }

procedure ThreadValue.Execute;
begin
  CSNO2_10 := TCriticalSection.Create;
  CSNO2_06 := TCriticalSection.Create;
  CSCompAir := TCriticalSection.Create;
  CSCoolant := TCriticalSection.Create;

Wenn ich nun mit meinem anderen Thread
Delphi-Quellcode:
type
  ThreadTCP = class(TThread)
  private
    { Private-Deklarationen }
    media: ThreadValue;
Versuche eine der Propertys aus zu lesen:
Delphi-Quellcode:
Self.FNO2_10 := media.NO2_10;
so sehe ich, beim debuggen, dass die Methode
Delphi-Quellcode:
CSNO2_10.Acquire; // lock out other threads
Immer einen Fehler verursacht und dadurch nie ein Wert gelesen werden kann.

Ich bin davon ausgegangen, dass mir eine lokale CriticalSection genügt, wenn diese in der "set" und "get" Methode eingebunden ist.

Vielen Dank für die weitere Hilfe runter vom Holzweg :(

chaosben 30. Sep 2011 05:55

AW: Datenaustausch zwischen Threads (Sync)
 
Die allseits beliebte Frage lautet: Welcher Fehler tritt auf?

Desweiteren brauchst du bei simplen Typen (Integer, ...) nur die Schreibzugriffe schützen.
Nur bei Daten, die nicht in einer Aktion geschrieben werden können, sollte man andere lesende Threads aussperren, damit sie keine "halben" Daten lesen.

FredlFesl 30. Sep 2011 06:59

AW: Datenaustausch zwischen Threads (Sync)
 
Zitat:

Zitat von fuchsle (Beitrag 1127480)
Delphi-Quellcode:
function ThreadValue.getNO2_10: Double;
begin
  try
    CSNO2_10.Acquire; // lock out other threads
    Result := FNO2_10;
  finally
    CSNO2_10.Release;
  end;
end;

Das Acquire muss vor das try.
Delphi-Quellcode:
MyCriticalSection.Acquire;
Try
  DoSomethingWhichMightCrash();
Finally
  MyCriticalSection.Release
End;

schlecki 30. Sep 2011 08:24

AW: Datenaustausch zwischen Threads (Sync)
 
Zitat:

Zitat von chaosben (Beitrag 1127596)
Desweiteren brauchst du bei simplen Typen (Integer, ...) nur die Schreibzugriffe schützen.

Und das afaik auch nur, wenn man den Wert vor dem Ändern ausliest, oder?
Wenn es denn eine atomare Änderung ist, braucht die nicht geschützt werden...

fuchsle 30. Sep 2011 11:48

AW: Datenaustausch zwischen Threads (Sync)
 
Zitat:

Zitat von schlecki (Beitrag 1127617)
Zitat:

Zitat von chaosben (Beitrag 1127596)
Desweiteren brauchst du bei simplen Typen (Integer, ...) nur die Schreibzugriffe schützen.

Und das afaik auch nur, wenn man den Wert vor dem Ändern ausliest, oder?
Wenn es denn eine atomare Änderung ist, braucht die nicht geschützt werden...

Wenn ich nur beim Schreiben schützen muss und nur ein Thread schreibt, so sollte ich mir jeglichen Schutz sparen können?
Geht es nicht darum zu verhindern, dass gelesen wird, wärend geschrieben wird?


Zitat:

Zitat von FredlFesl (Beitrag 1127601)
Zitat:

Zitat von fuchsle (Beitrag 1127480)
Delphi-Quellcode:
function ThreadValue.getNO2_10: Double;
begin
  try
    CSNO2_10.Acquire; // lock out other threads
    Result := FNO2_10;
  finally
    CSNO2_10.Release;
  end;
end;

Das Acquire muss vor das try.
Delphi-Quellcode:
MyCriticalSection.Acquire;
Try
  DoSomethingWhichMightCrash();
Finally
  MyCriticalSection.Release
End;

Habe ich gemacht.
sobald nun über den anderen Thread versucht wird die Property aus zu lesen, wird in der Funktion beim versuch das Aquire zu setzen abgebrochen.

Zitat:

Zitat von chaosben (Beitrag 1127596)
Die allseits beliebte Frage lautet: Welcher Fehler tritt auf?

Desweiteren brauchst du bei simplen Typen (Integer, ...) nur die Schreibzugriffe schützen.
Nur bei Daten, die nicht in einer Aktion geschrieben werden können, sollte man andere lesende Threads aussperren, damit sie keine "halben" Daten lesen.

Fehler: Zugriffsverletzung bei Adresse 005E4D 10 in Modul 'MediaController.exe'. Lesen von Adresse 00000064.

fuchsle 30. Sep 2011 12:08

AW: Datenaustausch zwischen Threads (Sync)
 
Erstmal Herzlichen Dank Euch allen!!

Ich habe einiges dazu gelernt und bin wirklich dankbar.
Leider muss ich zugeben, dass es, nicht anderst wie erwartet an mir lag.
Nach einigem hin und her, habe ich vergessen eine Zeile wieder aus zu kommentieren,
leider das Create für den Thread auf den ich zugriefen will.

Schande über mein Haupt :wall:

Nach dem Auskommentieren und der Berücksichtigung der letzten Kommentare geht es nun.


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