![]() |
Multithreading und Globale Funktionen
Hallo!
Ich muss einmal nachfragen bevor ich einen Blödsinn mache! Ich habe mehrere Threads. In einer globalen Unit habe ich dann z.B. diese Funktion:
Delphi-Quellcode:
Kann ich diese einfach im Thread verwenden oder kann es da zu Problemen führen?
function Add(a,b : Integer): Integer;
begin Result := (a + b); end; Es kann ja sein, dass der eine Thread gerade in der Funktion ist und dann ein anderer reinkommt. |
AW: Multithreading und Globale Funktionen
Das führt sogar mit großer Wahrscheinlichkeit zu Problemen.
|
AW: Multithreading und Globale Funktionen
Zitat:
Bei jedem Aufruf einer Funktion, werden die lokalen Variablen neu instantiiert. Jeder Aufrufer hat also seine eigene Instanz. In dem Beispiel hier gibt es noch nicht einmal Variablen. Anders würde es Aussehen bei globalen Vars. |
AW: Multithreading und Globale Funktionen
Zitat:
|
AW: Multithreading und Globale Funktionen
Die Funktion(en) haben natürlich auch Vars.
War ja nur ein Beispiel. Wenn aber für jeden Thread beim Aufruf eine eigene Instanz gemacht wird könnte es funktionieren. Das mit den globalen Variabeln ist mir dann auch klar! |
AW: Multithreading und Globale Funktionen
Eigentlich muss man sich die Grundfrage stellen, ob zwei Threads gleichzeitig auf die gleiche Variable zugreifen können.
Bei lokalen Variablen und bei Parametern schwierig, es sein denn das Referenzen (z.B. Objekte -> also Zeiger) übergibt. |
AW: Multithreading und Globale Funktionen
Ok,
die meisten globalen Vars sind eh TList und ich übergebe das Item als Pointer. Gefärlich wird es natürlich wenn die TList geändert wird aber ein anderer Thread noch damit arbeitet - also wenn das Item dann vielleicht gar nicht mehr da ist. Wie löst man dann sowas? Jeden Thread eine Kopie der TList geben. Die TList nur aus dem MainThread bearbeiten und nach dem Bearbeiten dem Thread die neue Liste übergeben!? |
AW: Multithreading und Globale Funktionen
Zitat:
Suche mal nach "Thread synchronisieren". Stichworte sind Semaphoren, critical sections, Mutex Grüße, Messie |
AW: Multithreading und Globale Funktionen
In Delphi gibt es eine spezialisierte TList dafür.
TThreadList |
AW: Multithreading und Globale Funktionen
Zitat:
Habe es nun eingebaut, jedoch geht es in einem Thread - im anderen nicht!? Ich mache es so in den Threads:
Delphi-Quellcode:
Es bleibt beim Locklist stehen.
var
List : TList; i : Integer; begin List := ALL_Names.Locklist; for i := 0 to List.Count - 1 do begin //do stuff with data end; ALL_Names.UnlockList; Der einzige Unerschied ist, dass es im dem Thread wo es nicht geht in der Thread.Execute ausgeführt wird. Im Thread wo es geht wird es per ein OnUDPRead Thread ausgeführt. Also der Thread hat einen UDP-Server mit einer OnUDPRead vom Thread. Da geht es ohne Probleme. Kann das LockList nicht im Execute vom Thread ausgeführt werden weil der Thread dann stehen bleibt und das Locklist nicht durchgeführt werden kann?? Ein zusätzliches ALL_Names.UnlockList davor bringt auch nichts. |
AW: Multithreading und Globale Funktionen
Grundsätzlich musst Du die Aufrufe LockList/Unlocklist ein einem Resourcenschutzblock kapseln. Das geht so:
Delphi-Quellcode:
Natürlich hängt der zweite Thread im LockList. Nämlich genausolange, wie der erste Thread sein UnlockList noch nicht aufgerufen hat.
MyLocalList := TheThreadList.LockList;
Try DoSomethingWith(MyLocalList); Finally TheThreadList.UnlockList; End; Mit dem Aufruf von "Locklist" öffnet Du die Tür zur Liste, zieht aber den Schlüssel von der Tür ab und macht hinter dir wieder zu. "Unlocklist" verlässt die Liste, schließt wieder ab und hinterlässt den Schlüssel. Der Aufruf von "LockList" wartet so lange, bis der Schlüssel wieder in der Tür steckt. |
AW: Multithreading und Globale Funktionen
Hallo,
wenn im anderen Thread die List gesperrt ist (locked) dann kann der zweite Thread nicht darauf zugreifen. Also nur die List sperren wenn Du darauf zugreifen willst. Grüße Klaus |
AW: Multithreading und Globale Funktionen
So schaut mein Thread (gekürzt) aus:
Delphi-Quellcode:
Wenn der Thread nun das Locklist aufruft steht er!?
constructor TNames_thread.Create(const MainWindowHandle : Thandle);
begin inherited create(True); // CreateSuspended = true FMainHandle := MainWindowHandle; FreeOnTerminate := False; end; procedure TNames_thread.Execute(); var Msg : TMsg; List: TList; len : Integer; begin while (not Terminated) do begin List := All_Names.Locklist; try len := List.Count; finally All_Names.Unlocklist; end; Sleep(1000); end; // while (not Terminated) do Terminate; end; Das ist bei beiden Threads gleich. Der was geht hat ja die OnUDPRead vom UDP Server und diese Funktion wird von einem andern Thread (TIdUDPListenerThread) ausgeführt. Dann kann das Locklist durchgeführt werden. Die All_Names Liste wird in der Mainform in der OnCreate erzeugt. EDIT: Fehler gefunden! Ich habe in der OnCreate im MainThread zuerst ein All_Names.Locklist.clear ausgeführt. danach aber kein Unlock! Jetzt geht's! |
AW: Multithreading und Globale Funktionen
Jetzt habe ich noch eine Frage zu dem Thema, aber mit einer anderen Funktion:
Delphi-Quellcode:
Kann man sowas für Multithread verwenden? Oder wird da das Result zurückgesetzt wenn gerade ein Thread in der For Schleife ist und ein anderer die GetString ausführt?
function GetString(Data : TBytes):String;
var i : Integer; begin Result := ''; for i := 0 to High(Data) do Result := Result + IntToHex(Data[i], 2); end; Oder muss es dann so gemacht werden:
Delphi-Quellcode:
Ich will sozusagen einen Logger machen. Wenn ich nun CriticalSection verwende ist der eine Thread solange blockiert bis der andere Thread durch ist. Dies führt zu einer nicht gewollten Verzögerung wenn es jetzt um viele Daten geht.
function GetString(Data : TBytes):String;
var i : Integer; begin EnterCriticalSection(CS); try Result := ''; for i := 0 to High(Data) do Result := Result + IntToHex(Data[i], 2); finally LeaveCriticalSection(CS); end; end; |
AW: Multithreading und Globale Funktionen
Das kommt auf die Daten an. Wenn diese Daten von mehreren Threads verändert/gelesen werden, muß eine Synchronisation stattfinden, ansonsten nicht. Es gibt zT sehr clevere Ansätze um parallel an großen Datensätzen zu arbeiten ohne daß sich die Threads in die Quere kommen.
Eine Frage hier wäre bspw., ob sich "Data" (durch einen anderen Thread) ändert, während es von dieser Funktion verarbeitet wird. Ohne weitere Infos kann man da keine konkreten Aussagen machen. |
AW: Multithreading und Globale Funktionen
Ne, Data gehört zu jedem Thread selber der die Funktion aufruft.
D.h. jeder Thread ruft die Funktion auf mit seinen eigenen privat deklariertden Data mit unterschiedlicher länge. Ich bin mir halt nicht sicher, wenn sich schon ein Thread in der Funktion befindet das Result von einem anderen Thread wieder mit dem Result :=''; wieder zurückgesetzt wird. Oder hat jeder Aufruf sein eigenes Result? Oder ob dadurch das High(Data) auch verbogen wird? Lokale Variabeln gelten ja für jeden eigenen Aufruf/Thread selber. |
AW: Multithreading und Globale Funktionen
Zitat:
Zitat:
|
AW: Multithreading und Globale Funktionen
Ok, danke!
Dann werde ich das mal probieren und sehen ob es zu Exceptions kommt. Mit dem "verbiegen" des High(Data) hatte ich gemeint, wenn der erste Thread z.B. mit Data[len=500] aufruft. Der zweite dann mit Data[len=3000]. Wenn nun auch i beim ersten Thread bis 2999 raufgezählt wird, dann gibt's natürlich Probleme weil der erste ja nur bis 499 geht. |
AW: Multithreading und Globale Funktionen
Zitat:
|
AW: Multithreading und Globale Funktionen
Bremst weniger aus.
Delphi-Quellcode:
Wobei ich mich immer frage, wie man auf soeine "kranke" Schleife kommt, mit soeiner Masse an langsamen Stringoperationen. :shock:
function GetString(Data : TBytes):String;
var Temp: TBytes; i : Integer; begin EnterCriticalSection(CS); try Temp := Copy(Data) finally LeaveCriticalSection(CS); end; Result := ''; for i := 0 to High(Temp) do Result := Result + IntToHex(Temp[i], 2); end; > ![]() Abgesehn davon würde ich nicht den Data-Parameter auf dieser Seite absichern, sondern ich würde auf der aufrufenden Seite das absichern, welches man an Data übergibt. |
AW: Multithreading und Globale Funktionen
Zitat:
Auch High() wird dir immer das richtige Ergebnis zurückliefern. Wäre auch schlimm wenn nicht ;) Zitat:
|
AW: Multithreading und Globale Funktionen
Zitat:
Code:
... in Sysutils.pas (RAD Studio 2009). Gibt's da irgendwelche Compiler-Magic oder wie weiß die aufgerufene Funktion über die Länge bescheid? Läuft das wie bei Strings? Habe mir nur noch nicht genügend Gedanken drüber gemacht, daher die Frage.
TBytes = array of Byte;
|
AW: Multithreading und Globale Funktionen
Danke für den Tipp mit BinToHex!
Das habe ich bis jetzt noch nie verwendet :oops: Ich habe mir die Strings halt immer so aus den TBytes erzeugt. Danke auch an jfheins! |
AW: Multithreading und Globale Funktionen
Zitat:
|
AW: Multithreading und Globale Funktionen
Zitat:
Muß wohl wieder mal Delphiprogramme reversen. Die kommen einem im natürlichen Habitat so selten unter ... muß´ also vorher selber schreiben und dann reversen :zwinker: |
AW: Multithreading und Globale Funktionen
Ich habe es nun auch live getestet.
3 Threads die die Funktion gleichzeitig nutzen. Ohne Critical Section. Keine Probleme! |
AW: Multithreading und Globale Funktionen
Funktionen und Prozeduren sind von Haus immer threadsafe, weil alle lokalen Variablen bei jedem Aufruf neu erzeugt werden. Wäre dem nicht so, könnte man auch keine rekursiven Aufrufe von Proc und Funk machen.
Das Problem sind immer nur die Daten auf die dabei zugegriffen wird. Also alles was nicht lokal zur Proc/Func gehört kann potentiell kritisch sein. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 16:22 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