Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Berechnungs-Threads die lesend auf Dynamische Arrays zugreif (https://www.delphipraxis.net/133953-berechnungs-threads-die-lesend-auf-dynamische-arrays-zugreif.html)

tobias_sdr 12. Mai 2009 21:39


Berechnungs-Threads die lesend auf Dynamische Arrays zugreif
 
Hallo alle miteinander,

ich habe folgendes Problem und benötige zur Lösung eure Hilfe.

Ich fülle einen TCollection mit "Jobs"; sprich jedes Item der TCollection besitzt die Parameter, mit denen dann ein Thread seine Berechnungen durchführen soll. Sprich mein Hauptthread legt den Pool an und befüllt diesen auch. Gleichzeitig über
Delphi-Quellcode:
WaitForSingleObject(aJobList.Semaphore, INFINITE)
prüfen die anderen Threads, ob in dem Pool Jobs sind. Sind welche vorhanden, soll sich jeder einen nehmen und berechnen, solange bis der Pool leer ist. In dieser Zeit soll der Hauptthread nach Beendigung des Füllens auf die Abarbeitung der Jobs und die Beendigung der Berechnung warten. Die Threads sollen aktiv bleiben.

Die Threads greifen während ihrer Berechnung lesend auf eine gemeinsame Datenstrucktur aus Dynamischen Arrays zu, die nur von dem Hauptthread beschrieben wird nachdem der Pool leer ist und die Threads fertig sind. Ich habe hier im Forum gelesen, dass Dynamische Arrays zu Problemen führen können. Leider weiß ich nicht, wie ich das umgehen soll. Eine Syncronisierung jedes Zugriffes würde doch wahrscheinlich zur Verlangsamung des Programms führen, oder?


Woran kann das liegen?

Blup 14. Mai 2009 08:57

Re: Berechnungs-Threads die lesend auf Dynamische Arrays zug
 
Wenn nur lesend gleichzeitig auf das Array zugegriffen wird, dürfte das nicht zu Problemen führen.
Allerdings würde ich es vermeiden den Referenzzähler von Strings, Arrays oder Interfaces dabei zu verändern.
Wenn solche Werte als Parameter übergeben werden, dann nach Möglichkeit immer als const-Parameter.
Das aber eher aus Gründen der Geschwindigkeit, insbesondere wenn mehrere Prozessoren auf den selben Speicher zugreifen.

Ansonsten schau mal in der Delphi-Hilfe nach diesen Stichworten:
TThread
TCriticalSection
TMultiReadExclusiveWriteSynchronizer

Insbesondere Zugriffe auf den Pool sollten z.B. durch TCriticalSection abgesichert sein.

tobias_sdr 14. Mai 2009 10:15

Re: Berechnungs-Threads die lesend auf Dynamische Arrays zug
 
Hallo und erst mal Danke für die Antwort,

die Dyn.-Array sind als "Global" über eine Unit in die Threads-Unit eingebunden. Der Zugriff auf den Pool erfolgt über Semapore und das Lesen und Schreiben über Mutex. Ich dachte auch, dass der Fehler da liegt. Wenn ich aber die Berechnungseinheit der Threads in eine Exception kapsele wird der Fehler abgefangen. Ich habe aber nur lesenden Zugriff in den Berechnungsthreads. Mein Hauptthread vergrößert die Dyn-Array nach jeden Berechnungsdurchlauf um das Ergebnis.

Zu deinem Vorschlag
Zitat:

Allerdings würde ich es vermeiden den Referenzzähler von Strings, Arrays oder Interfaces dabei zu verändern.
Leider weiß ich nicht, wie ich das machen soll? :(

Danke nochmal für deine Hilfe

Uwe Raabe 14. Mai 2009 10:49

Re: Berechnungs-Threads die lesend auf Dynamische Arrays zug
 
Zitat:

Zitat von tobias_sdr
Ich habe aber nur lesenden Zugriff in den Berechnungsthreads. Mein Hauptthread vergrößert die Dyn-Array nach jeden Berechnungsdurchlauf um das Ergebnis.

Ich denke, da sitzt das Problem! DynArrays sind ja eigentlich nichts anderes als Pointer auf ein Array bestimmter Größe. Beim Vergrößern des DynArrays wird bei Bedarf neuer Speicherplatz an ganz anderer Stelle zugewiesen, das Array dorthin kopiert und der Pointer angepasst. Der alte Speicherplatz wird freigegeben und kann für andere Sachen verwendet werden. Wenn nun während einer Berechnung im Neben-Thread der Haupt-Thread das DynArray verschiebt, arbeitet der Neben-Thread auf dem falschen Speicherbereich.

Um es mal so auszudrücken: "Nur-Lesen" bei mehreren Threads gilt immer auch für den Haupt-Thread. Sobald einer schreibt sollte man synchronisieren. Es mag zwar Fälle geben, wo das unnötig ist, aber wer garantiert denn, daß das bei der nächsten Programmänderung bzw. beim nächsten Delphi- oder Windows-Update so bleibt?

tobias_sdr 14. Mai 2009 11:02

Re: Berechnungs-Threads die lesend auf Dynamische Arrays zug
 
Danke, so hab ich das auch Verstanden.

Mein Haupthread wartet über
Delphi-Quellcode:
WaitForSingleObject(ajobList.fEventJob.Handle,5000);
auf die Abarbeitung des Jobpools und mit

Delphi-Quellcode:
WaitForSingleObject(MyThreadSemaphore.fEventThread.Handle,5000);
auf die Beendigung der Threads erst danach werden die Ergebnisse vom Haupthread geschrieben.

Kann ich das Problem durch Nutzung von TCollection anstelle von Dyn.-Arrays umgehen?

Danke für eure Hilfe.

pertzschc 14. Mai 2009 11:22

Re: Berechnungs-Threads die lesend auf Dynamische Arrays zug
 
Schau auch mal folgende Diskussion an: WorkerThread
Gruß,
Christoph

Blup 15. Mai 2009 10:36

Re: Berechnungs-Threads die lesend auf Dynamische Arrays zug
 
Zitat:

Zitat von tobias_sdr
Der Zugriff auf den Pool erfolgt über Semapore und das Lesen und Schreiben über Mutex. Ich dachte auch, dass der Fehler da liegt.

Ich würde die Semapore durch TCriticalSection ersetzen und wirklich jeden lesenden und schreibenden Zugriff auf den Pool darüber nur innerhalb von Enter und Leave.

WaitForSingleObject(ajobList.fEventJob.Handle,5000 );
Ist sichergestellt, das wirklich alle Jobs bereits durch einen Thread bearbeitet werden/wurden?

WaitForSingleObject(MyThreadSemaphore.fEventThread .Handle,5000);
Ist sichergestellt, das wirklich der letzte Thread beendet wurde?

Zitat:

Zitat von tobias_sdr
Wenn ich aber die Berechnungseinheit der Threads in eine Exception kapsele wird der Fehler abgefangen.

Es tritt also tatsächlich ein Fehler auf, wie lautet die Fehlermeldung? Zugriffsverletzung?
Ich würde den Fehler auf jeden Fall bei den oben genannten Punkten suchen.

Zitat:

Zitat von tobias_sdr
Zu deinem Vorschlag
Zitat:

Allerdings würde ich es vermeiden den Referenzzähler von Strings, Arrays oder Interfaces dabei zu verändern.
Leider weiß ich nicht, wie ich das machen soll? :(

Zitat:

Wenn solche Werte als Parameter übergeben werden, dann nach Möglichkeit immer als const-Parameter.
Das kann aber kein Ursache für die Exception sein.


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