![]() |
Threadsicherheit
Guten Abend,
in letzter Zeit befasse ich mich deutlich mehr mit Assembler und begebe mich, wie der Titel vielleicht schon verrät, in das Gebiet der Threads, sehr spannend, vorallem in Assembler. :roll: Threads benutzen ist eine Sache, sie sicher zu benutzen eine andere. Während ich also arbeitet stellten sich mir einige Fragen, die eigentlich aus einem recht simplen Kontext entstanden. Nehmen wir einfach mal das Beispiel für einen Referenzzähler, so wie TInterfacedObject es für uns macht. Ich kann mich vage erinnern, dass die Release-Methode ungefähr so aussah:
Delphi-Quellcode:
Sinngemäß sollte es das sein, analog dazu die AddRef-Methode:
procedure TInterfacedObject._Release();
begin InterlockedDecrement(refcount); if refcount = 0 then Free(); end;
Delphi-Quellcode:
Wahrscheinlich hat sich schon einiges geändert oder stimmt so nicht, doch ich glaube das trifft das Ganze schon ziemlich genau. Nun Sinn der Nutzung von InterlockedIncrement resp. InterlockedDecrement ist in meinen Augen natürlich die Threadsicherheit. Zwischen dem Lesen, Manipulieren und Schreiben des Wertes kann kein andere Thread auf diesen zugreifen, bzw. anders gesagt, es wird als eine Operation angesehen ( atomic-operation ), in Assambler dem lock-Prefix entsprechend.
procedure TInterfacedObject._AddRef();
begin InterlockedIncrement(refcount); end; Nun stellt sich mir aber die Frage, ist das wirklich threadsicher? Folgendes Beispiel:
Code:
Nun, das ist für mich alles andere als sicher. Darum kam mir der Gedanke, benutzen wir doch einfach mal kritische Abschnitte. Packen wir außen rum und alles ist super. Naja ~
Thread1 ruft _Release() auf.
Der Zähler wird gesenkt: InterlockedDecrement(refcount); Der Wert wird geladen und verglichen, entsprechend folgt eine Sprungoperation oder nicht, schließlich der Call if refcount = 0 then Free(); Kontextwechsel beim aufruf von Free. Ich meine mich zu erinnern irgendwo mal gelesen zu haben, dass hauptsächlich nach jumps, calls, rets o.Ä. ein solcher Hardwarekontextwechsel passiert. Thread2 ruft _AddRef() auf. Der Zähler wird erhöht. InterlockedIncrement(refcount); ... Erneuter Kontextwechsel. Thread1 führt nun fleißig Free aus. Die Daten sind nicht mehr im Speicher, Thread2 ist sich aber sicher über seinen Besitz des Objektes. Unaufhaltsam rast Thread2 nun in eine Zugriffsverletzung. Die CriticalSection will auch initialisiert und finalisiert werden, wie fast alles andere am Computer. Folgendes Szenario: Unser erster Thread betritt nun diese kritische Sektion, für alle anderen ist es gesperrt, er ist nun in der Lage das Objekt und die damit verbundene kritische Sektion wieder zu finalisieren, was ja auch richtig ist, wenn das Objekt gelöscht wird, ist für die kritische Sektion kein bedarf mehr. Aber was ist mit unserem zweiten Thread, der nun vielleicht schon darauf wartet die kritische Sektion zu betreten ( ich rede jetzt von EnterCriticalSection z.b. ). ![]() Zitat:
Ich kann natürlich so argumentieren, dass ich sage, es ist ein Designfehler meines Programms, wenn so etwas passieren kann, doch ich denke, das ganze lässt sich auch auf andere Themen übertragen. Schönen Abend noch ;D |
AW: Threadsicherheit
Du kannst nicht "treadsicher" direkt auf diese Variable zugreifen.
Delphi-Quellcode:
Theoretisch würde jetzt dennoch knallen, wenn zur selben Zeit _AddRef und _Release aufgerufen wird, wenn das InterlockedIncrement kurz nach InterlockedDecrement aufgerufen würde, da das Objekt freigegeben, aber praktisch sollte sowas nie passieren.
procedure TInterfacedObject._Release();
var i: Integer; begin i := InterlockedDecrement(refcount); if i = 0 then Destroy; end; Denn wurde die letzte Referenz freigegeben, kann diese Variable keine Referenz mehr abgeben und somit kann sowas nie passieren. Solange keiner an der Referenzzählung rumspielt und nirgendwo eine "Referenz" existiert, welcher nicht in der Referenzzählung enthalten ist. |
AW: Threadsicherheit
Zitat:
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 08:13 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