![]() |
CriticalSections wie verwenden?
Umzug der CriticalSection Diskusion aus
verhindern: Klick auf Titelleiste stoppt Programm #27 ![]() @Sir Rufo Zitat:
Mir ist nicht ganz klar was Du damit schützt, die Bereiche innerhalb Deiner Klasse die nicht von anderen Threads erreicht werden können brauchen IMHO nicht mit einer CriticalSection gekapselt werden. Wenn Du einen Bereich in eine CriticalSection packst mußt Du Dich so zumindest mein Kenntnissstand darauf verlassen können daß andere über die gleich CriticalSection darauf zugreifen. Hast Du Punkt #26 aus o.g. Thread einmal nachvollzugen? Die Variable txt ist nur sicher zugreifbar wenn sich alle daran halten vor dem Zugriff ein und dieselbe CriticalSection zu verwenden. |
AW: CriticalSections wie verwenden?
Zitat:
Zitat:
Ich nehme allerdings an, daß hier nur die Ausdrucksweise unglücklich war. Wenn der Getter und Setter (oder ggf. nur Setter, je nach Datentyp) den kritischen Abschnitt benutzen, ist das ja nicht auf einen Thread beschränkt, wie die Aussage erstmal vermuten läßt. |
AW: CriticalSections wie verwenden?
Zitat:
|
AW: CriticalSections wie verwenden?
Zitat:
Zitat:
|
AW: CriticalSections wie verwenden?
Liste der Anhänge anzeigen (Anzahl: 1)
Um das mit den CriticalSections mal etwas besser zu verdeutlichen habe ich mal mein WorkThread-Beispiel etwas umgeändert um folgende Situationen darzustellen:
- optimales Laufzeitverhalten mit einem Minimum an Störungen des Threads durch Zugriffe von außen (bzw. durch den Event, der ja in einem anderen Thread-Kontext läuft und somit auch einen Zugriff von außen darstellt) - blockierndes Laufzeitverhalten durch ein ungeschicktes Verwenden von CS - Deadlock durch CS Mit den beiden Compilerschaltern kann der Thread entsprechend eingestellt werden.
Delphi-Quellcode:
Wenn man jetzt die Laufzeiten von optimal und blockierend betrachtet (deadlock läuft ja gar nicht) dann sieht man folgendes:
unit uWorkThread;
{.$DEFINE DEADLOCK} {.$DEFINE BLOCKING} interface uses Generics.Collections, Classes, SyncObjs; type TWorkItem = record TimeStamp : TDateTime; end; TWorkQueue = TQueue< TWorkItem >; TWorkNotify = procedure( WorkItem : TWorkItem ) of object; TWorkType = ( wtSync, wtQueue ); TWorkThread = class( TThread ) private { Private-Deklarationen } FCSWork : TCriticalSection; FCSQueue : TCriticalSection; FCSWorkType : TCriticalSection; FWorkQueue : TWorkQueue; FOnWork : TWorkNotify; FWorkType : TWorkType; procedure DoOnWork; procedure SetOnWork( const Value : TWorkNotify ); function GetOnWork : TWorkNotify; procedure SetWorkType( const Value : TWorkType ); function GetWorkType : TWorkType; protected procedure Execute; override; public property WorkType : TWorkType read GetWorkType write SetWorkType; property OnWork : TWorkNotify read GetOnWork write SetOnWork; constructor Create( CreateSuspended : Boolean ); destructor Destroy; override; end; implementation uses SysUtils; { TProgressThread } constructor TWorkThread.Create( CreateSuspended : Boolean ); begin FCSWork := TCriticalSection.Create; FCSQueue := TCriticalSection.Create; FCSWorkType := TCriticalSection.Create; FCSWork.Enter; FCSQueue.Enter; FCSWorkType.Enter; try inherited; FWorkQueue := TWorkQueue.Create; FWorkType := wtSync; finally FCSWork.Leave; FCSQueue.Leave; FCSWorkType.Leave; end; end; destructor TWorkThread.Destroy; begin FCSWork.Enter; FCSQueue.Enter; FCSWorkType.Enter; try FWorkQueue.Free; inherited; finally FCSWork.Leave; FCSQueue.Leave; FCSWorkType.Leave; FreeAndNil( FCSWork ); FreeAndNil( FCSQueue ); FreeAndNil( FCSWorkType ); end; end; procedure TWorkThread.DoOnWork; var WorkItem : TWorkItem; begin FCSWork.Enter; try WorkItem := FWorkQueue.Dequeue; finally FCSWork.Leave; end; {$IFDEF BLOCKING} FCSWork.Enter; {$ELSE} FCSQueue.Enter; {$ENDIF} try if Assigned( FOnWork ) then FOnWork( WorkItem ); finally {$IFDEF BLOCKING} FCSWork.Leave; {$ELSE} FCSQueue.Leave; {$ENDIF} end; end; procedure TWorkThread.Execute; var WorkItem : TWorkItem; Counter : Integer; begin { Thread-Code hier einfügen } Counter := 0; while not Terminated and ( Counter < 1000 ) do begin WorkItem.TimeStamp := Now; Inc( Counter ); FCSWork.Enter; try FWorkQueue.Enqueue( WorkItem ); finally FCSWork.Leave; end; {$IFDEF DEADLOCK} FCSWork.Enter; try {$ENDIF} case WorkType of wtSync : Synchronize( DoOnWork ); wtQueue : Queue( DoOnWork ); end; {$IFDEF DEADLOCK} finally FCSWork.Leave; end; {$ENDIF} //Sleep( 10 ); end; end; function TWorkThread.GetOnWork : TWorkNotify; begin {$IFDEF BLOCKING} FCSWork.Enter; {$ELSE} FCSQueue.Enter; {$ENDIF} try Result := FOnWork; finally {$IFDEF BLOCKING} FCSWork.Leave; {$ELSE} FCSQueue.Leave; {$ENDIF} end; end; function TWorkThread.GetWorkType : TWorkType; begin FCSWorkType.Enter; try Result := FWorkType; finally FCSWorkType.Leave; end; end; procedure TWorkThread.SetOnWork( const Value : TWorkNotify ); begin {$IFDEF BLOCKING} FCSWork.Enter; {$ELSE} FCSQueue.Enter; {$ENDIF} try FOnWork := Value; finally {$IFDEF BLOCKING} FCSWork.Leave; {$ELSE} FCSQueue.Leave; {$ENDIF} end; end; procedure TWorkThread.SetWorkType( const Value : TWorkType ); begin FCSWorkType.Enter; try FWorkType := Value; finally FCSWorkType.Leave; end; end; end. Erstellung: Zeitpunkt der Erstellung im Thread Ausgabe: Zeitpunkt der Ausgabe in der ListBox optimal
Code:
Der Thread hat nach 6/1000 Sekunden alle 1000 Einträge erzeugt.
Erstellung Ausgabe
============ ============ 01:43:52.380 - 01:43:52.381 01:43:52.380 - 01:43:52.382 01:43:52.380 - 01:43:52.384 01:43:52.380 - 01:43:52.392 01:43:52.380 - 01:43:52.394 01:43:52.380 - 01:43:52.395 01:43:52.380 - 01:43:52.397 01:43:52.380 - 01:43:52.397 01:43:52.380 - 01:43:52.399 ... 01:43:52.386 - 01:43:53.961 Bis zu diesem Zeitpunkt wurden 3 Einträge in die ListBox eingetragen. Erzeugung und Ausgabe laufen aber parallel, die Ausgabe dauert halt nur länger als die Erstellung blockierend
Code:
hier erfolgt nun entweder die Ausgabe oder die Erstellung, aber keine parallele Verarbeitung.
Erstellung Ausgabe
============ ============ 01:42:10.625 - 01:42:10.626 <- Ausgabe erfolgt 01:42:10.625 - 01:42:10.626 ... 01:42:10.626 - 01:42:10.671 01:42:10.626 - 01:42:10.673 01:42:10.626 - 01:42:10.675 <- Erstellung stoppt 01:42:10.673 - 01:42:10.677 <- Erstellung geht weiter 01:42:10.673 - 01:42:10.679 01:42:10.673 - 01:42:10.681 ... Source und Exe im Anhang |
AW: CriticalSections wie verwenden?
Zitat:
Der Zugriff aus einem anderen Thread passiert ja über die Getter und Setter bzw. die entsprechende Property und damit wird der Zugriff auch effektiv geschützt. Und dabei muss dennoch nicht mit dem Hauptthread synchronisiert werden, sondern es wird nur die kritische Sektion benutzt. Nicht funktionieren tut es, wenn der Zugriff auf eine Resource eben nicht immer über die selbe kritische Sektion erfolgt. Aber das ist hier nicht der Fall, da jeder Thread zwar eine eigene kritische Sektion, aber auch eine eigene zu schützende Resource hat. |
AW: CriticalSections wie verwenden?
Danke , aber wenn jeder Thread seien eigen CriticalSection erzeugt wie ist dann ein übergreifender Zugriff gewährleistet, oder da dies ja nicht eigentlich das Problem hier ist, wofür benötige ich die Threadinternen CS überhaupt?
|
AW: CriticalSections wie verwenden?
Zitat:
Beispiel:
Delphi-Quellcode:
Meine Variante sieht so aus
GlobalCS : TCriticalSection;
TMyThread = class( TThread ) {...} Info : Int64; end; procedure TMyThread.Execute; begin while not Terminated do begin GlobalCS.Enter; try QueryPerformanceCounter( Info ); finally GlobalCS.Leave; end; end; end; MyThread1, MyThread2 : TMyThread; procedure ImMainThread; var ThInfo : Int64; begin GlobalCS.Enter; // Beide Threads MyThread1, MyThread2 stoppen jetzt, weil sie ja // GlobalCS nicht mehr betreten können. // Ich will aber nur von MyThread1 etwas wissen, warum soll MyThread2 dann gestört werden??? try ThInfo := MyThread1.Info; finally GlobalCS.Leave; end; end;
Delphi-Quellcode:
Der Zugriff auf die Property ist wesentlich leichter und es wird nur der Thread gestört, den ich abfrage.TMyThread = class( TThread ) ThreadCS : TCriticalSection; FInfo : int64; {...} property Info : Int64 read GetInfo; end; function GetInfo : Int64; begin ThreadCS.Enter; try Result := FInfo; finally ThreadCS.Leave; end; end; procedure TMyThread.Execute; begin while not Terminated do begin ThreadCS.Enter; try QueryPerformanceCounter( FInfo ); finally ThreadCS.Leave; end; end; end; MyThread1, MyThread2 : TMyThread; procedure ImMainThread; var ThInfo : Int64; begin ThInfo := MyThread1.Info; end; |
AW: CriticalSections wie verwenden?
Zitat:
b. der Thread selber ist per Definition auch threadsafe für Zugriffe von außen (über die Properties) meine Threads übernehme ich in jedes beliebige Projekt und benutze diese ohne mich um irgendeine CS weiter zu kümmern, dann das regelt der Thread ja in sich selber. Greift Thread A auf eine Property aus Thread B zu, dann ist die Property von Thread B ja geschützt. Somit kann es einfach keine Zugriffsfehler geben, da diese immer geschützt sind. Ist quasi die Merz-Spezial-Dragee-Methode (Wahre Schönheit kommt von innen) :mrgreen: |
AW: CriticalSections wie verwenden?
@Sir Rufo
Das eben macht mir Kopfschmerzen #9 b Wenn Du für jede Instanz eine eigene CS erzeugst wie soll der Zugriff dann geschützt sein. Aber ich muß jetzt ins Bett, gerne morgen weiter:thumb: |
AW: CriticalSections wie verwenden?
Zitat:
Das heißt es geht nicht darum, auf die selbe Resource mit verschiedenen kritischen Sektionen zuzugreifen, wie du offenbar vermutest. |
AW: CriticalSections wie verwenden?
Zitat:
Meine Delphikenntnisse sind ein wenig eingerostet, aber ich sehe in deinem Code keinen konkurrierenden Zugriff zwischen den Threads. Was willst du also beweisen? Daß dein Code sicher ist, wäre zumindest damit nicht (generell) bewiesen. Zitat:
Das was ich gesehen habe wäre aber ohnehin billiger mit Interlocked-Funktionen zu machen (zumindest bei den verwendeten Datentypen). Zitat:
Zusammenfassend: Also, es gibt nicht nur eine Queue, somit ist die Queue auch pro Thread schützbar (so wie gezeigt). |
AW: CriticalSections wie verwenden?
Zitat:
Und ich schütze mit der Thread-internen CS den Speicherbereich der Instanz und nicht von allen Instanzen, was zwar möglich ist, aber überflüssig. Stell dir vor ein Kühlschrank darf nur immer von einem geöffnet werden, weil sonst geht die Welt unter. Bei deiner Methode mit der globalen CS würde das bedeuten, dass auf der ganzen Welt niemand einen Kühlschrank öffnen darf, nur weil ich gerade meinen geöffnet habe (da hatte ich aber Glück). Und erst wenn ich die Türe schließe, darf der nächste. Wenn ich böse bin, dann pfeife ich auf die Stromkosten, bzw. melde mich bei "e wie einfach" an und lasse den Rest der Welt verdursten. Bei meiner Methode gilt das nur für den Kühlschrank, von dem ich etwas nehmen will. Alle anderen Kühlschränke interessieren mich nicht (und laut Definition auch nicht notwendig, da jeder Kühlschrank ja auch einen eigenen Speicherbereich hat, die ich nicht alle schützen muss, wenn ich meinen Kühlschrank öffne). |
AW: CriticalSections wie verwenden?
Um bei Deinem Beispiel zu bleiben
Point.x Point.y in einer CriticalSection, wenn der lesende sich nicht darum schert daß es da eine (ihm unbekannte CS) gibt liest er einfach den Wert aus , egal ob der Thread es in eine CS gepackt hat oder nicht. |
AW: CriticalSections wie verwenden?
@assabard
Delphi-Quellcode:
aber wofür benötigt er dann ene CS?
Wenn jeder Thread seine eigene Queue hat und mit der CS schützt, dann macht es schon so Sinn. Da der Zugriff über Getter/Setter stattfindet, hat alles seine Ordnung.
|
AW: CriticalSections wie verwenden?
Zitat:
|
AW: CriticalSections wie verwenden?
Zitat:
Es ist egal, ob das von einer lokalen (im Thread verankerten) oder globalen CS geschützt wird. Es muss aber geschützt werden. Aber wozu alles schützen, wenn ich genau bestimmen kann, was geschützt werden soll? (Sippenhaft und Singleton sind entweder nicht zulässig oder verpönt) :mrgreen: |
AW: CriticalSections wie verwenden?
Jepp, aber hier kommen wir wieder zu dem Punkt daß die Abfrage sich nicht für Deine lokalen CS interessiert.
wenn Du nochmals mein Beispiel aus ![]() #26 heranziehst Meine Vorstellung einer CS basiert darauf daß ein Codeabschnitt markiert Windows mitgeteilt wird. Wenn ein anderer Thread versucht diesen Codeabschnitt zu betreten wird dies nur ermöglicht wenn kein anderer Thread sich gerade darin aufhält. Wenn die Markierung jedes mal eine andere ist wie soll Windows hier eingreifen. |
AW: CriticalSections wie verwenden?
Zitat:
|
AW: CriticalSections wie verwenden?
Zitat:
In seinem Beispiel befindet sich das Feld, auf das zugegriffen wird, innerhalb des Threads. Und es wird ausschließlich über die kritische Sektion genau dieses Threads zugegriffen. Und eben nicht durch verschiedene Threads und mehrere Sektionen. Denn beim Zugreifen verwendet auch der andere Thread die kritische Sektion des Zielthreads und nicht seine eigene. |
AW: CriticalSections wie verwenden?
@jaenicke
Nochmals Danke dies ist mir meine ich klar, aber wofür dann die CS wenn sich ohnehin alles innerhalb des Threads abspielt. Ich scheine hier tatsächlich einen resistenten Hänger zu haben, mir erschließt sich der Sinn der lokalen CS nicht, die ja nur berücksichtigt werden können wenn ein potentieller "Zugreifer" davon Kenntnis hat. |
AW: CriticalSections wie verwenden?
Zitat:
|
AW: CriticalSections wie verwenden?
Zitat:
Ich muss nun gewährleisten, dass bei jedem Zugriff auf den Speicherbereich A die CS CSA betreten und danach wieder verlassen wird. Das ist erstmal alles. Windows ist es egal, wieviele CS ich benutze. Jede Instanz von einer Klasse/Thread belegt einen bestimmten Speicherbereich. Erzeuge ich mit der Klasse/Thread eine CS kann ich damit genau den Speicherbereich vom der Klassen-/Thread-Instanz schützen. Meine Vorgehensweise ist nun, dass alles in der Klasse/Thread, auf das von außen zugegriffen wird von eben so einer CS geschützt wird.
Delphi-Quellcode:
Wenn ich jetzt auf die Property Info von der Thread-Instanz zugreife, warum sollte die dann nicht geschützt sein?
TMyThread = class( TThread )
property Info : Int64 read GetInfo; end; function TMyThread.GetInfo : Int64; begin ThreadCS.Enter; try Result := FInfo; finally ThreadCS.Leave; end; end; Es wird ein CS betreten, der Wert ausgelesen und die CS wieder verlassen. Das diese CS-Instanz innerhalb der Thread-Instanz aufgehangen ist, ist völlig egal. Es ist eine CS. Und schützen muss ich die mit einer CS, wenn ich den Wert der Property Info innerhalb von TMyThread.Execute beschreiben will
Delphi-Quellcode:
procedure TMyThread.Execute;
begin ThreadCS.Enter; try FInfo := 20; finally ThreadCS.Leave; end; end; |
AW: CriticalSections wie verwenden?
warum funktioniert dann folgendes
![]() #26 wenn hier der zugreifende die CS ignoriert, bwz eine ander nimmt bekommt er Zugriff die der Intention der CS wiederspricht. |
AW: CriticalSections wie verwenden?
Zitat:
Wir haben Threads A und B sowie Ressourcen a(A) und b(B) die jeweils dem Thread gehören. A besitzt eine CS die den Zugriff auf a(A) regelt und B eine CS die den Zugriff auf b(B) regelt. Soweit kommst du sicher mit, richtig? Wenn nun aber Thread A einen Zugriff auf die Instanz von B macht, ruft er (im eigenen Kontext, also dem Kontext von Thread A ... das ist der potentielle Konflikt) die Getter oder Setter von B auf (aber mit Self == B). Dieser Getter oder Setter benutzt aber auch die CS welche den Zugriff auf b(B) regelt und damit ist alles in Ordnung. |
AW: CriticalSections wie verwenden?
Zitat:
In Sir Rufos Code hast du genau eine kritische Sektion für genau eine Resource. |
AW: CriticalSections wie verwenden?
Zitat:
Delphi-Quellcode:
Das im Thread (also in einem anderen Thread als der HauptThread)
procedure TForm1.Button1Click(Sender: TObject);
var tc:Cardinal; begin FCS.Enter; txt := 'Button1'; tc := GetTickCount; while GetTickCount < (tc + 5000) do Application.ProcessMessages; Showmessage(txt); FCS.Leave; end;
Delphi-Quellcode:
Das Perverse daran ist, das funktioniert tatsächlich ... aber das hier würde auch funktionieren:
procedure TMyThread.Execute;
begin inherited; FCS2.Enter; txt := 'Thread'; FCS2.Leave; end;
Delphi-Quellcode:
Erst wenn der HauptThread und der Thread gleichzeitig schreibend/lesend oder schreibend/schreibend auf die Variable txt zugreifen, erst dann und nur dann gibt es einen Zugriffsfehler.
procedure TForm1.Button1Click(Sender: TObject);
var tc:Cardinal; begin txt := 'Button1'; tc := GetTickCount; while GetTickCount < (tc + 5000) do Application.ProcessMessages; Showmessage(txt); end; procedure TMyThread.Execute; begin inherited; txt := 'Thread'; end; Die CS ist nicht dazu da, dass es überhaupt funktioniert, sondern dass es immer funktioniert. Allerdings wirst du bei diesem COde es wahrscheinlich niemals eine Zugriffsverletzung bekommen, da der Thread ja nur einen winzigen Moment läuft und genau diesen Zeitpunkt müsstest du treffen, um eine Zugriffsverletzung zu provozieren. Nach dem Klicken von dem Button für das Starten des Threads, vergeht aber mehr Zeit, bis die Form wieder Eingaben zulässt, als der Thread mit der abarbeitung von Execute benötigt ... darum brauchst du hier gar keine CS, weil der Zustand so gesehen niemals eintrifft :mrgreen: |
AW: CriticalSections wie verwenden?
dann muss ich allen Beteiligten erst einmal Abbitte leisten. Der Getter/Setter stellt sicher dass ich mich in der richtigen CS befinde, habe ich das richtig verstandenen?
|
AW: CriticalSections wie verwenden?
Zitat:
|
AW: CriticalSections wie verwenden?
Genau.
Ich war auch erstmal verblüfft. Aber Kommentar #9 hat dann auch den Sinn hinter den CS pro Thread aufgezeigt. Ab da war's absolut klar. Tut mir leid wenn ich zur Verwirrung beigetragen haben sollte. Man sollte eben den kompletten Kontext kennen :zwinker: |
AW: CriticalSections wie verwenden?
@Assarbad
muss Dir nicht Leid tun, ich war komplett vernagelt. Ich danke nochmals Sir Rufo, Jaenicke und Assbard für ihre Bemühungen. |
AW: CriticalSections wie verwenden?
Könnte man nicht das auch so beschreiben:
In dem „Universum“ gibt es zwei Personen und zwei Häuser. Jede Person stellt ein Thread dar, und jedes Haus dessen Speicherbereich. Eine CriticalSection ist jetzt wie eine Tür: Wenn jetzt die Person A auf eine Variable der Person B zugreift (z.B. den Stromzählerstand ablesen), dann geht die Person A in das Haus von B und liest den Zählerstand ab. Aber währenddessen kann ja die Person B den Zähler manipulieren. D.h. Solange die Person B daran arbeitet schließt sie die Tür ab (betritt also die CriticalSection) und wenn sie fertig ist, verlässt sie das Haus (bzw. die CriticalSection). Diese CriticalSection befindet sich dabei im Haus B (ist ja auch die Tür von Haus B). Solange kommt die Person A (oder jemand anderes) ran. MfG Fabian |
AW: CriticalSections wie verwenden?
Um von einem anderen Thema wegzukommen in welchem es ein bisschen ins OffTopic bzgl CriticalSections ging knüpfe ich hier mit einer Frage an.
Angenommen ich erstelle 2 oder mehr Threads, die alle ein und das gleiche tun nur jeweils eine eigene Liste mit bestimmten Informationen haben. Zur Anzeige schickt jeder Thread eine Message an einen anderen Thread (um diese Zeile Code ist aktuell ein CriticalSectionLocal.Enter und Leave drum), welcher ein Label ändert (diesen Thread gibt es nur 1x). In diesem GUI-Thread hole ich die Message mit GetMessage. Soweit erstmal Horror-Code #1, ist mir aber egal und darauf BITTE nicht eingehen! Die Frage lautet nun: bringt es irgendetwas eine globale CriticalSection VOR der Erstellung der 2 oder mehr Threads zu betreten und am Ende aller Arbeit wieder zu verlassen? Somit würde ich doch jeder der 2+ Threads in dieser einen, globalen Critical Section befinden. Oder sollte jeder Thread seine eigene, lokale CriticalSection haben? Daraus bin ich bis hier hin leider noch nicht schlau geworden. Außerdem... braucht man mit einer CriticalSection Synchronize(procedure bla.Caption := '123'; end); innerhalb eines Threads noch? Das Thema scheint wohl öfter aufzukommen ob mehrere lokal oder eine global: ![]() |
AW: CriticalSections wie verwenden?
Zitat:
Mit einer CriticalSection sperrst du eine globale Ressource (z.B.: globale Variable) für den Zugriff durch andere. Wenn du fertig bist, gibst du den Zugriff wieder frei. Wer zwischendurch drauf zugreifen will, muss warten. Stelle es dir einfach wie eine Toilette (= Ressource, die man i.d.R. alleine benutzen möchte) vor, das Türschloss ist die CriticalSection. Damit stellt man sicher, dass man alleine ist. Natürlich muss jeder, der die Toilette betritt, auch das Türschloss benutzen, sonst funktioniert es nicht (es darf auch keiner durch das Fenster einsteigen). Du hast in deinem Beispiel übrigens mehrere Leute in der Toilette eingeschlossen, und wartest bis alle Fertig sind, um sie wieder rauszulassen. Dabei sind sogar alle gleichzeitig am ******, was für eine Sauerei. Wenn du allerdings auf VCL-Komponenten zugreifen willst brauchst du zwingend ein Synchronize oder du verschickst eine Message (SendMessage / PostMessage). |
AW: CriticalSections wie verwenden?
Heißt also auch eigentlich, dass eine lokale im Thread selbst erzeugte CriticalSection genau so sinnfrei ist wie eine die um den ganzen Code drum rum ist.
|
AW: CriticalSections wie verwenden?
Zitat:
|
AW: CriticalSections wie verwenden?
Das kam mir gleich sehr seltsam vor mit der lokalen CriticalSection. Denn wie soll Thread1 denn von der CriticalSection von Thread2 erfahren? Also ist das eher Quatsch.
Gut dann habe ich das wenigstens umgestellt und werde mir merken: WENN (!) es nicht anders geht, dann Synchronize für GUI und schreiben (nicht lesen?) von globalen Variablen nur mit globaler CriticalSection ("global"... es ist eine Unit mit Records und Classes). |
AW: CriticalSections wie verwenden?
Zitat:
Für viele Lese- und wenige Schreibzugriffe gibt es auch noch ![]() |
AW: CriticalSections wie verwenden?
Zitat:
Dem Zitat oben entnehme ich, dass eine normale CriticalSection auch anderen Threads den nur-lesen-Zugriff nicht erlaubt? Bitte sag mir, dass ich falsch liege. Thread1 geht in Prozedur XYZ > CriticalSection.Enter > setzen von globaler Variable 123 > CriticalSection.Leave Währenddessen kann Thread2 nicht lesen auf globale Variable 123 zugreifen? |
AW: CriticalSections wie verwenden?
Während eines Schreibzugriffes darf nicht gelesen werden.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:07 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