Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Thread: Direkt auf die Form zugreifen? (https://www.delphipraxis.net/42993-thread-direkt-auf-die-form-zugreifen.html)

Helmi 27. Mär 2005 10:52


Thread: Direkt auf die Form zugreifen?
 
Hallo,

mich würde es interessieren was ihr dazu denkt:

Ich habe einen Thread der eine for-Schleife hat.
In dieser Schleife wird von einer ListView die Zeilen nacheinander abgearbeitet und die einzelnen Spalten ausgelesen.
Die ListView liegt auf der Form1.

Ich würde gerne das so umbauen, dass der Thread nicht direkt auf die Form1 und somit direkt auf die ListView zugreifen muss, sondern ich würde gerne dem Thread vor dem Starten die ListView irgendwie übergeben.

Ich hab schon an eine StringList etc. gedacht, die ich vor dem Starten des Threads mit den aktuellen Inhalten der ListView beschreibe, aber ich benutz auch die CheckBoxen der ListView. Diese werden auch in der Schleife abgefragt.

Was meint ihr?
Ist es in Ordnung, dass der Thread in der Schleife auf die Form1 zugreift oder wie würdet ihr das machen?

P.S.: ich hoffe ihr wisst was ich mein.

[edit] Titel vergessen :wall:

jfheins 27. Mär 2005 11:08

Re: Thread: Direkt auf die Form zugreifen?
 
Zitat:

Zitat von Helmi
Ist es in Ordnung, dass der Thread in der Schleife auf die Form1 zugreift ?

Wenn die ListView ein Element der VCL ist, was ich mal annehme, dann ist das nicht in Ordnung.

Dann müsstest du in dem Thread eine ListView unterbringen, und deine ListView beim Start kopieren ...

SirThornberry 27. Mär 2005 11:11

Re: Thread: Direkt auf die Form zugreifen?
 
oder einfach eine TList nehmen und mit records der gewünschten daten füllen.

Helmi 27. Mär 2005 19:09

Re: Thread: Direkt auf die Form zugreifen?
 
Wie meinst du das mit der TList?

hab mit der noch keine Erfahrung.
Kann ich bei der auch ne CheckBox übergeben?

Helmi 29. Mär 2005 14:22

Re: Thread: Direkt auf die Form zugreifen?
 
Hallo Jungs,

ich hab mich jetzt doch entschieden eine 2. ListView (nicht visuell) zu benutzen
(genauer gesagt es war ein Tip eines C++-Programmieres)

Jetzt hätt ich dazu noch ne frage:
Wo soll ich jetzt diese ListView erzeugen?
In der Form1? - bei OnCreate und bei OnDestroy wieder freigeben?

oder im Execute des Threads am Anfang erzeugen und am Ende wieder freigeben?

Michael_Bayer 29. Mär 2005 14:35

Re: Thread: Direkt auf die Form zugreifen?
 
Zitat:

Zitat von jfheins
Zitat:

Zitat von Helmi
Ist es in Ordnung, dass der Thread in der Schleife auf die Form1 zugreift ?

Wenn die ListView ein Element der VCL ist, was ich mal annehme, dann ist das nicht in Ordnung.

Dann müsstest du in dem Thread eine ListView unterbringen, und deine ListView beim Start kopieren ...

Woran liegt da das Problem? :gruebel:

Ich habe auch viele Threads, die aktiv an Elementen auf meiner Form rumschmieren - ist das nicht okay?

Kedariodakon 29. Mär 2005 15:02

Re: Thread: Direkt auf die Form zugreifen?
 
Eigendlich nicht :roll:
Meist geht sowas gut, aber sobald da ein Pentium mit HT oder nen REchner mit Dual Prozis dazukommt geht nix mehr, obwohl, Fehlermeldungen gehen noch :zwinker:


Bye

Mephistopheles 29. Mär 2005 15:20

Re: Thread: Direkt auf die Form zugreifen?
 
Das hat etwas mit Synchronisation zu tun. Selbst wenn es ein Uniprocessor-System ist, auf dem es nur eine quasi-parallele Abarbeitung der Threads gibt, kann es passieren, daß ein Thread Speicher freigibt/-gab und während ein anderer versucht darauf zuzugreifen. Bei Objekten wird das ganze noch viel komplexer und ist irgendwann unüberschaubar.

Daher sollte man entweder Ausschlußobjekte (z.B. Mutexe, Semaphoren, Critical Sections) benutzen um jeweils nur einem Thread Zugriff zu gewähren oder bei 32bit(bzw. Bitzahl der CPU)-großen Einzelwerten die Interlocked*-Funktionen verwenden. Alles andere ist nicht nur unsauberer Programmierstil sondern kann auch Multi-Processor-Systemen (oder auch HT-Systemen, bei sind ja im Kommen) zu bösen schwer nachvollziehbaren Fehlern führen. Also Finger weg von der VCL aus Threads heraus. Sauberer Stil ist sowieso, daß der Thread nur ein Fenster benachrichtigt und dieses Fenster dann die Daten von einer vorher vereinbarten Stelle abholt. Danach wird dem Thread wieder signalisiert, daß er auf diese Stelle wieder schreiben darf usw. usf.

Helmi 29. Mär 2005 15:39

Re: Thread: Direkt auf die Form zugreifen?
 
Hallo,

ich hab mir das so vorgestellt:
(wenn was zum aussetzen ist, bitte melden)

In dem Thread-Execute mach ich folgendes:
Delphi-Quellcode:
procedure TUpdatethread.Execute;
begin
  try
    //Thread-ListView erzeugen
    Thread_ListView := TListView.Create;

    Synchronize(CopyListView);

    Updaten;

  finally
    //Thread-ListView freigeben und löschen
    FreeAndNil(Thread_ListView);
  end;
end;
die Procedure "CopyListView" schaut so aus:
Delphi-Quellcode:
procedure TUpdatethread.CopyListView;
begin
  Thread_ListView.Assign(Form1.ListView_Dateien);
end;
kann man das so lassen oder gibts was auszusetzen?

Michael_Bayer 29. Mär 2005 16:12

Re: Thread: Direkt auf die Form zugreifen?
 
Zitat:

Zitat von Mephistopheles
Das hat etwas mit Synchronisation zu tun. Selbst wenn es ein Uniprocessor-System ist, auf dem es nur eine quasi-parallele Abarbeitung der Threads gibt, kann es passieren, daß ein Thread Speicher freigibt/-gab und während ein anderer versucht darauf zuzugreifen. Bei Objekten wird das ganze noch viel komplexer und ist irgendwann unüberschaubar.

Daher sollte man entweder Ausschlußobjekte (z.B. Mutexe, Semaphoren, Critical Sections) benutzen um jeweils nur einem Thread Zugriff zu gewähren oder bei 32bit(bzw. Bitzahl der CPU)-großen Einzelwerten die Interlocked*-Funktionen verwenden. Alles andere ist nicht nur unsauberer Programmierstil sondern kann auch Multi-Processor-Systemen (oder auch HT-Systemen, bei sind ja im Kommen) zu bösen schwer nachvollziehbaren Fehlern führen. Also Finger weg von der VCL aus Threads heraus. Sauberer Stil ist sowieso, daß der Thread nur ein Fenster benachrichtigt und dieses Fenster dann die Daten von einer vorher vereinbarten Stelle abholt. Danach wird dem Thread wieder signalisiert, daß er auf diese Stelle wieder schreiben darf usw. usf.

Hmm..würde das so funktionieren, dass ich ein globales Array aufbaue und dem Thread mitgebe, er soll in Array[1] die Lösung stecken, wenn er fertig ist?

Oder nochbesser: Kann ich dem Thread sagen, es soll die Lösung in eine Procedure als Parameter übergeben, und die Procedure ändert dann die VCL?

Oder muss ich das so machen, dass ich eine globale Variable Editable mache, die ich auf false setze, wenn ein Thread gerade ein VCL-Element ändert?

Mephistopheles 29. Mär 2005 17:28

Re: Thread: Direkt auf die Form zugreifen?
 
Zitat:

Zitat von Michael_Bayer
Hmm..würde das so funktionieren, dass ich ein globales Array aufbaue und dem Thread mitgebe, er soll in Array[1] die Lösung stecken, wenn er fertig ist?

Ja, aber nicht ohne Exclusion-Objects (s.o.). Bzw. wenn es ein Integerarray ist, kannst du die Interlocked*-Funktionen verwenden.

Zitat:

Zitat von Michael_Bayer
Oder nochbesser: Kann ich dem Thread sagen, es soll die Lösung in eine Procedure als Parameter übergeben, und die Procedure ändert dann die VCL?

Da du diese Prozedur ja vom 2. Thread aus aufzurufen scheinst kann das keine Lösung sein. Denn die Prozedur läuft dann im Kontext dieses Threads.

Zitat:

Zitat von Michael_Bayer
Oder muss ich das so machen, dass ich eine globale Variable Editable mache, die ich auf false setze, wenn ein Thread gerade ein VCL-Element ändert?

Selbst das ist nur mit Interlocked*-Funktionen sicher, da ansonsten ein Thread die Variable auslesen könnte, obwohl du in einem anderen schon "Bla := False" gesagt hast. Wohlgemerkt, das ist hypothetisch (in der Praxis wird es auf einem Uniprocessor-System quasi nie zu Problemen kommen).

Versuchen wir mal die Vorstellungskraft zu forcieren (ein besseres Beispiel fiel mir nicht ein):

Stell dir den Code (jede Seite ein Zeitscheibenintervall ausgeführten Codes) als ein Buch vor und die Daten (jede Seite eine beliebige komplexe Datenstruktur - eine Datenstruktur kann natürlich auch mehrere Seiten umfassen) als ein anderes.
Hast du einen Prozessor, so kann im Codebuch nur eine Seite gleichzeitig aufgeschlagen sein. Bei mehreren Prozessoren entspricht die maximale Anzahl gleichzeitig aufgeschlagener ("ausgeführter") Seiten der Anzahl Prozessoren. Nun ist es so, daß in dem Datenbuch auch mehrere Seiten existieren. Eine Seite stellt dabei eine komplexe Datenstruktur dar.
Da wir aber mit mehreren parallelen oder quasi-parallelen Threads arbeiten, kann es passieren, das Thread#1 auf Seite#1 schreibt. Nun sagt das Zeitscheibenprinzip, daß Thread#1 irgendwann eingefroren wird und Thread#2 an der Reihe ist. Leider passiert aber das Einfrieren, während Thread#1 nur etwa 1/3 der Seite#1 geschrieben hat. Thread#2 ist nun also an der Reihe. Da Thread#2 auch an Seite#1 interessiert ist, versucht es dorthin zu schreiben - natürlich vom Anfang der Seite#1. Da Thread#2 etwas optimaler kodiert ist, kann Thread#2 vor dem Einfrieren ganze 50% der Datenstruktur schreiben. Nun ist Thread#3 an der Stelle, welcher die Daten aus Seite#1 gern auslesen möchte. Tut er auch. Nun die Quizfrage: was steht auf Seite#1? Was steht nach einem 2ten Durchgang auf Seite#1? Ist dies das gewünschte Verhalten?

Nun kannst du dir ein Ausschlußobjekt so vorstellen, daß Thread#2 und #3 zwar an die Reihe kommen, jedoch sehen, daß Seite#1 gerade beschrieben wird. Deshalb warten Sie weiter und geben die Kontrolle direkt wieder ab. Statt Threads kannst du auch Prozesse annehmen und statt einer Buchseite eine einzelne Datei - aber bei Dateien gibt es andere Ausschlußmechanismen.

Helmi 29. Mär 2005 17:44

Re: Thread: Direkt auf die Form zugreifen?
 
nebenbei bemerkt: Ich hätt da oben ein kleines Problem

Mephistopheles 29. Mär 2005 17:51

Re: Thread: Direkt auf die Form zugreifen?
 
Zitat:

Zitat von Helmi
nebenbei bemerkt: Ich hätt da oben ein kleines Problem

Ich weiß ...
Zitat:

Zitat von Helmi
kann man das so lassen oder gibts was auszusetzen?

Ja gibt es. Man kann alles so lassen, nur korrekt ist es eben nicht ;) ... meine Antwort über deiner Frage:
Zitat:

Zitat von Helmi
nebenbei bemerkt: Ich hätt da oben ein kleines Problem

...sollte dir Auskunft geben was falsch ist.

Übrigens: Synchronize() führt den Code im Hauptthread des Prozesses aus (zumindest war dies mindestens bis Delphi 5 so). TThread ist eigentlich relativ ungeeignet für Multithread-Anwendungen. Allerdings ist die VCL mindestens bis Delphi 6 auch nicht multithread-safe gewesen ;) ... die aktuellen Versionen kenne ich nicht. Es gibt ja aber auch noch F1 :lol:

Helmi 29. Mär 2005 17:55

Re: Thread: Direkt auf die Form zugreifen?
 
aber ich hab doch nur einen Thread und keine Multi-thread-Anwendung

und wie mach ich das mit der ListView?
wie erzeug ich sie wo am besten auf?

Mephistopheles 29. Mär 2005 18:01

Re: Thread: Direkt auf die Form zugreifen?
 
Häh? :shock:
Ich sehe doch da ein TThread-abgeleitetes Objekt in deinem Code? Dir ist schon bewußt, daß jeder Prozess mindestens einen (Haupt-)Thread hat? Wieviel hat dein Prozess, wenn du noch einen hinzufügst? Würdest du deine Behauptung, daß 2 Threads nicht multi-threaded sind noch aufrecht erhalten wollen?

;)

Helmi 29. Mär 2005 18:07

Re: Thread: Direkt auf die Form zugreifen?
 
ist ja alles schön und recht das mit dem Multi-Threads ja oder nein

aber ich wollt das eigentlich alles ned wissen

Ich wollt nur das mit der ListView wissen

irgendwie werden gerade zwei themen zusammen geschmissen, die normalerweise zwei (DP-)Threads sind.

Bleiben wir bitte nur bei einem Thema - also der ListView

Mephistopheles 29. Mär 2005 18:11

Re: Thread: Direkt auf die Form zugreifen?
 
Zitat:

Zitat von Helpmi
irgendwie werden gerade zwei themen zusammen geschmissen, die normalerweise zwei (DP-)Threads sind.

Nein werden sie nicht, denn das Updaten von VCL-Elementen (z.B. deinem ListView) in einem separaten Thread ist ganz simpel: ziemlich gefährlich.

Helmi 29. Mär 2005 18:15

Re: Thread: Direkt auf die Form zugreifen?
 
und wie dann?

der einer sagt: ja, es geht, der andere sagt: nein - zu gefährlich

was jetzt?

Michael_Bayer 29. Mär 2005 19:28

Re: Thread: Direkt auf die Form zugreifen?
 
Zitat:

Zitat von Helmi
und wie dann?

der einer sagt: ja, es geht, der andere sagt: nein - zu gefährlich

was jetzt?

Ja es geht (wär ja blöd, wenn nicht) - jedoch sind bestimmte Regeln zu beachten. (s.o.)

Also wie ich das verstanden habe, muss man vor dem kritischen Bereich (dem Ändern eines VCL-Objektes) die "critical section" "entern" und danach wieder "leaven".
Meine Frage nun: Wenn ich die critical section betrete, woher wissen dann die anderen Threads, welches Objekt sie nicht anfassen dürfen? (Dass die Threads dann komplett stillstehen, kann ja nicht sein)

EDIT: Ahhhh verstanden :bounce2: - Wenn ich eine CriticalSection betrete, dann bin nur ich darin und alle, die auch etwas "kritisches" machen wollen, müssen warten.
So muss ich überall, wo etwas zusammenhauen könnte, die CriticalSection benutzen.

Allerdings kommt mir das etwas.. naja.. ineffektiv vor.
Ich muss ja dann auch bei Leseoperationen auf ein Objekt, dass woanders geschrieben werden könnte, eine CriticalSection benutzen - so werden ja auch Leseoperationen serialisiert...muss das sein?

EDIT2: Aber das Problem könnte ich ja minimieren, wenn ich für JEDES Objekt eine eigene CriticalSection erstelle. So sitze ich dann zum Schluss vielleicht mit 20 CS rum, aber gehen sollte das. (Gibts eine logische Grenze für CriticalSections?)

Mephistopheles 29. Mär 2005 20:09

Re: Thread: Direkt auf die Form zugreifen?
 
Zitat:

Zitat von Michael_Bayer
Also wie ich das verstanden habe, muss man vor dem kritischen Bereich (dem Ändern eines VCL-Objektes) die "critical section" "entern" und danach wieder "leaven".
Meine Frage nun: Wenn ich die critical section betrete, woher wissen dann die anderen Threads, welches Objekt sie nicht anfassen dürfen? (Dass die Threads dann komplett stillstehen, kann ja nicht sein)

Ganz einfach. Jeder Thread der auf ein bestimmtes Objekt (sei es ein Integer, ein Array oder ein String) zugreift, sollte vorher in die Critical Section gehen. Der Code danach sollte IMMER in einem try-finally-Block stehen, damit die CritSect auch verlassen wird!

Zitat:

Zitat von Michael_Bayer
EDIT: Ahhhh verstanden :bounce2: - Wenn ich eine CriticalSection betrete, dann bin nur ich darin und alle, die auch etwas "kritisches" machen wollen, müssen warten.
So muss ich überall, wo etwas zusammenhauen könnte, die CriticalSection benutzen.

Exakt. Und sobald du ein weiteres Objekt einführst wo mehrere Threads lesen und schreiben, führst du eine neue CritSect ein. So können die Threads auch dann noch die zweite Sache abarbeiten, während es bei der ersten vielleicht nicht geklappt hat.

Zitat:

Zitat von Michael_Bayer
Allerdings kommt mir das etwas.. naja.. ineffektiv vor.
Ich muss ja dann auch bei Leseoperationen auf ein Objekt, dass woanders geschrieben werden könnte, eine CriticalSection benutzen - so werden ja auch Leseoperationen serialisiert...muss das sein?

Anders geht es nicht. Denn genau das ist ja das Problem, wenn sich mehrere Codeteile eine Ressource teilen. Der Punkt ist ja gerade, daß du die Geschichte so effektiv wie möglich gestalten sollst und kannst, indem du die rechenintensiven Sachen sinnvoll trennst und parallelisierst. Das ist aber ein eigenes Themengebiet der Informatik und kann sicherlich nicht in Gänze in einem solchen Thread hier abgehandelt werden ;)

Michael_Bayer 29. Mär 2005 22:24

Re: Thread: Direkt auf die Form zugreifen?
 
Sind Pointer eigentlich "Treadsafe"?
Wenn ich zb einen Eintrag in einem VirtualStringTree ändern möchte.
Ich hole mit das Node in der CriticalSection und setze einen Pointer auf seine Daten.

Kann ich jetzt ausserhalb der CriticalSection mit Hilfe des Pointers die Daten verändern? (Wenn kein anderer genau auf das Ziel des Pointers schreiben möchte)

EDIT: Um mal auf die VCL zurückzukommen - sind Functionen wie "VCL-Objekt.Refresh" oder ähnliches threadsafe?

Mephistopheles 30. Mär 2005 07:40

Re: Thread: Direkt auf die Form zugreifen?
 
Zitat:

Zitat von Michael_Bayer
Sind Pointer eigentlich "Treadsafe"?
Wenn ich zb einen Eintrag in einem VirtualStringTree ändern möchte.
Ich hole mit das Node in der CriticalSection und setze einen Pointer auf seine Daten.

Kann ich jetzt ausserhalb der CriticalSection mit Hilfe des Pointers die Daten verändern? (Wenn kein anderer genau auf das Ziel des Pointers schreiben möchte)

Benutz' einfach InterlockedExchange() oder InterlockedExchangePointer() (eins von beiden war nicht deklariert in meiner Delphiversion) statt "bla := bla2" und schon bist du fein raus ;)

Zitat:

Zitat von Michael_Bayer
EDIT: Um mal auf die VCL zurückzukommen - sind Functionen wie "VCL-Objekt.Refresh" oder ähnliches threadsafe?

Die VCL ist meines Wissens vollständig nicht thread-safe.

Michael_Bayer 30. Mär 2005 08:15

Re: Thread: Direkt auf die Form zugreifen?
 
Zitat:

Zitat von Mephistopheles
Zitat:

Zitat von Michael_Bayer
Sind Pointer eigentlich "Treadsafe"?
Wenn ich zb einen Eintrag in einem VirtualStringTree ändern möchte.
Ich hole mit das Node in der CriticalSection und setze einen Pointer auf seine Daten.

Kann ich jetzt ausserhalb der CriticalSection mit Hilfe des Pointers die Daten verändern? (Wenn kein anderer genau auf das Ziel des Pointers schreiben möchte)

Benutz' einfach InterlockedExchange() oder InterlockedExchangePointer() (eins von beiden war nicht deklariert in meiner Delphiversion) statt "bla := bla2" und schon bist du fein raus ;)

Kann ich hier nicht auch eine CriticalSection benutzen? Falls ja, warum exisitieren dann so viele andere Arten von "Threadsicherung"? Was gibt mit InterlockedExchange, was mir eine Critical Section nicht gibt?


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