![]() |
Delphi-Version: XE2
Kurze Frage zur Thread Sicherheit
Hi, ist es sicher, wenn ein Thread lesend und schreibend auf ein Index eines Array zugreift und ein anderer Thread lesend und schreibend auf das gleiche Array mit einem anderen Index zugreift? Oder müssen alle Zugriffe synchronisiert werden?
|
AW: Kurze Frage zur Thread Sicherheit
Sollte theoretisch sicher sein, solange wirklich immer nur ein Thread auf einen Index gleichzeitig zugreift.
|
AW: Kurze Frage zur Thread Sicherheit
OK, danke für die Antwort.
|
AW: Kurze Frage zur Thread Sicherheit
Und sich das Array selber nicht verändert, also kein SetLength und Co.
Was ist das denn für ein Array? |
AW: Kurze Frage zur Thread Sicherheit
Hallo luke2,
du kannst dafür am besten einen MREW benutzen. Damit können mehrere Threads gleichzeitig lesend drauf zugreifen, aber immer nur einer schreibend. Natürlich müssen beide Threads die gleiche Instanz von dem TSafeArray bekommen ;) Bei so kritischen Sachen würde ich nie wie du vorhast die Array Instanz einem Thread direkt mitteilen. Dies ist eine vereinfachtere Variante die ich gerade im Einsatz habe: Das ist an sich eigentlich schon ziemlich performant, aber du könntest jetzt ein lokales Array/Liste etc. anlegen, die alle Lesezugriffe auf die versch. Indexe speichert. Und beim Schreiben wird dann geprüft ob dieser Index in der Liste ist, wenn ja muss dort beim zugreifen eben gewartet werden. Aber ich würde das mit dem gleichzeitigen auf ein Index auch sein lassen und immer als schreibend behandeln.
Delphi-Quellcode:
Grüße
uses
// Delphi Math, // OmniThreadLibrary OtlSync; type TSafeArray = class private FArray: array of Integer; FLock: TOmniMREW; public constructor Create; procedure SetResult(AIndex: Integer; const AValue: Integer); function GetResult(AIndex: Integer): Integer; end; constructor TSafeArray.Create; begin SetLength(FArray, 0); end; procedure TSafeArray.SetResult(AIndex: Integer; const AValue: Integer); begin FLock.EnterWriteLock; try SetLength(FArray, Max(AIndex, length(FArray)) + 1); // Lesezugriff: length(); Schreibzugriff!: SetLength() FArray[AIndex] := AValue; // Schreibzugriff: FArray[Index] finally FLock.ExitWriteLock; end; end; function TSafeArray.GetResult(AIndex: Integer): Integer; var Index: Integer; begin Result := -1; Index := AIndex; FLock.EnterReadLock; // starte das lesen try if Index < length(FArray) then // Lesezugriff: length() Result := FArray[Index]; // Lesezugriff: FArray[Index] finally FLock.ExitReadLock; // beende das lesen end; end; |
AW: Kurze Frage zur Thread Sicherheit
Danke, das sieht gut aus, geskill, aber ich möchte eigentlich keine externen Komponenten benutzen.
Es sieht ungefähr so aus:
Delphi-Quellcode:
Add wird aus dem Hauptthread aufgerufen. Use ist natürlich anfangs immer False und wird vom Thread auch irgendwann wieder auf False gesetzt. Das sollte doch sicher sein?
type
T = record Str: string; Use: Boolean; end; private A: Array[0..5] of T; procedure TThread.Add(const S: string); begin with A[GetFreeField] do begin Str := S; Use := True; end; end; procedure TThread.Execute; begin while not Terminated do begin for I := Low(A) to High(A) do if Use then begin //hier werden nur Felder von A[I] gelesen und geändert end; Sleep(1); end; end; |
AW: Kurze Frage zur Thread Sicherheit
Also wenn du Add() aufrufst bevor der Thread startet, dann geht das in Ordnung.
Nur so musst du das immer wissen, wann du es aufrufen darfst. Bei kleinen Programmen ist das noch in Ordnung, aber man sollte sich besser direkt angewöhnen das sauber umzusetzen. In dem Beispiel bei mir kann man dies ohne zu überlegen einfach aufrufen. Das Auslesen passiert dann auch erst wieder wenn der Thread definitiv beendet wurde (z.B. via Join)? Da es ein statisches Array ist sind die Schreibtugriffe ja wirklich nur aus die einzelnen Elemente begrenzt. Und mit 2 Threads meinst du Hauptthread und TThread - oder? ;) |
AW: Kurze Frage zur Thread Sicherheit
Zitat:
Zitat:
Kann man dein Beispiel auch mit den Windows CriticalSections (TRTLCriticalSection) umsetzen, so dass keine externe Unit/Komponente benutzt werden muss? |
AW: Kurze Frage zur Thread Sicherheit
Die Schleife ist ja kurz und bei den heutigen leistungsstarken PC gehört schon ein bisschen Glück dazu das ein Fehler Auftritt. Weil beim Add() schreibst du ja auf einen Index I und bei jedem lesen greifst du immer auf Used von I lesend zu. Das ist nicht in Ordnung.
Mit einer TCriticalSection kannst du das nun einschränken. Der Vorteil bei den OTL Sections ist das man sie nicht initialisieren und freigeben muss. Zudem ist der MREW auch "sicherer" als der von Delphi. |
AW: Kurze Frage zur Thread Sicherheit
OK, vielen Dank. Eine letzte Frage: Ist es denn so sicher (auch wenn es keine optimale Lösung ist)?
Delphi-Quellcode:
type
T = record Str: string; Use: Boolean; end; private A: Array[0..5] of T; CS: TRTLCriticalSection; procedure TThread.Add(const S: string); begin EnterCriticalSection(CS); try with A[GetFreeField] do begin Str := S; Use := True; end; finally LeaveCriticalSection(CS); end; end; procedure TThread.Execute; begin while not Terminated do begin for I := Low(A) to High(A) do begin EnterCriticalSection(CS); if Use then begin LeaveCriticalSection(CS); //hier werden nur Felder von A[I] gelesen und geändert end else LeaveCriticalSection(CS); end; Sleep(1); end; end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:41 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