![]() |
Interlocked* mit Operator Überladung
Hallo,
ist das Ganze so Threadsafe, oder koennte es Probleme geben?
Delphi-Quellcode:
Grüße, Win32.API
type
TThreadSafeInteger = record private Value: Integer; public class operator Add(a: TThreadSafeInteger; b: Integer): Integer; class operator Subtract(a: TThreadSafeInteger; b: Integer): Integer; class operator Implicit(a: TThreadSafeInteger): Integer; class operator Implicit(a: Integer): TThreadSafeInteger; class operator Explicit(a: TThreadSafeInteger): Integer; class operator Explicit(a: Integer): TThreadSafeInteger; end; implementation { TThreadSafeInteger } class operator TThreadSafeInteger.Add(a: TThreadSafeInteger; b: Integer): Integer; begin InterlockedExchangeAdd(a.Value, b); InterlockedExchange(result, a.Value); end; class operator TThreadSafeInteger.Subtract(a: TThreadSafeInteger; b: Integer): Integer; begin InterlockedExchangeAdd(a.Value, -b); InterlockedExchange(result, a.Value); end; class operator TThreadSafeInteger.Explicit(a: TThreadSafeInteger): Integer; begin InterlockedExchange(result, a.Value); end; class operator TThreadSafeInteger.Implicit(a: TThreadSafeInteger): Integer; begin InterlockedExchange(result, a.Value); end; class operator TThreadSafeInteger.Explicit(a: Integer): TThreadSafeInteger; begin InterlockedExchange(result.Value, a); end; class operator TThreadSafeInteger.Implicit(a: Integer): TThreadSafeInteger; begin InterlockedExchange(result.Value, a); end; |
Re: Interlocked* mit Operator Überladung
Delphi-Quellcode:
Fazit: hier ist garnichts geschützt, da alles nur intern abläuft und extern kein Schutz besteht.
class operator TThreadSafeInteger.Add(a: TThreadSafeInteger; b: Integer): Integer;
begin a.Value := a.Value + b; // sinnlos, da hier nur eine Kopie von a verändert wird // und kein anderer darauf zugreifen kann result := a.Value; // lesezugriff end; class operator TThreadSafeInteger.Subtract(a: TThreadSafeInteger; b: Integer): Integer; begin a.Value := a.Value - b; // siehe add result := a.Value; // lesezugriff end; class operator TThreadSafeInteger.Explicit(a: TThreadSafeInteger): Integer; begin result := a.Value; // Lesezugriffe brauchen hier nicht geschützt werden, // da es die Schreibzugriffe schon ausreichend machen end; class operator TThreadSafeInteger.Implicit(a: TThreadSafeInteger): Integer; begin result, a.Value); end; class operator TThreadSafeInteger.Explicit(a: Integer): TThreadSafeInteger; begin result.Value := a; // sinnloas, da Result intern eh won keinem Anderem // gesetzt werden kann und die externe Zuweisung ist vollkommen ungeschützt end; class operator TThreadSafeInteger.Implicit(a: Integer): TThreadSafeInteger; begin result.Value := a; // siehe vorher end; Man benötigt vorallem bei den Schreibvorgängen direkten Zugriff auf die Variablen und das ist via Result nicht möglich. |
Re: Interlocked* mit Operator Überladung
Dankeschoen fuer die Erklaerung, gibt es eine Moeglichkeit sowas zu implementieren, oder muss ich weiterhin die unschoenen Api Calls in meinem Programm verwenden?
|
Re: Interlocked* mit Operator Überladung
sowas könnte gehn
Delphi-Quellcode:
theoretisch ginge auch sowas,
type
TThreadSafeInteger = record private Value: Integer; public class operator Implicit(a: TThreadSafeInteger): Integer; procedure Put (i: Integer); procedure Add (i: Integer); procedure Subtract(i: Integer); procedure Inc; procedure Dec; property Get: Integer read Value; end; class operator TThreadSafeInteger.Implicit(a: TThreadSafeInteger): Integer; begin result := a.Value; end; procedure TThreadSafeInteger.Put(i: Integer); begin InterlockedExchange(Value, i); end; procedure TThreadSafeInteger.Add(i: Integer); begin InterlockedExchangeAdd(Value, i); end; procedure TThreadSafeInteger.Subtract(i: Integer); begin InterlockedExchangeAdd(Value, -i); end; procedure TThreadSafeInteger.Inc; begin InterlockedIncrement(Value); end; procedure TThreadSafeInteger.Dec; begin InterlockedDecrement(Value); end;
Delphi-Quellcode:
wenn da nicht der blöde Fehler im LOCK MOV wäre
class operator TThreadSafeInteger.Implicit(a: TThreadSafeInteger): Integer;
asm //mov eax, &a end; procedure TThreadSafeInteger.Put(i: Integer); asm lock mov [&Self], &i end; procedure TThreadSafeInteger.Add(i: Integer); asm lock add [&Self], &i end; procedure TThreadSafeInteger.Subtract(i: Integer); asm lock sub [&Self], &i end; procedure TThreadSafeInteger.Inc; asm lock inc [&Self] end; procedure TThreadSafeInteger.Dec; asm lock dec [&Self] end; Zitat:
|
Re: Interlocked* mit Operator Überladung
Vielen Dank fuer deine Muehe, aber wenn ich z.b. "sowas könnte gehn" oder "theoretisch ginge auch sowas" lese, bin ich sehr skeptisch, ob ich es in einer Anwendung einsetzen sollte.
Grueße, Win32.API |
Re: Interlocked* mit Operator Überladung
Zitat:
PS: die Compare-Operatoren kannst du genauso wie den Lese-Operator noch mit einbinden, da es ja auch nur Lesezugriffe sind. und das "theoretisch" hieß, daß es irgendwie geht, wenn man 'nen Umweg für LOCK MOV V, i einsetzt und z.B. LOCK AND V, 0 und danach noch LOCK ADD V, i verwendet, aber das ist nicht unbedingt so die optimalste Lösung, da der Wert ja für ein paar Takte auf 0 steht :? |
Re: Interlocked* mit Operator Überladung
Generell ist diese Interlocked-Sache von der Theorie ganz nett, aber in der Praxis meistens einfach doch zu aufwendig.
Es gibt fast kein Problem, bei dem man früher oder später nicht sowieso zu "gröberen" Locks greifen muss, warum also sich so den Kopf zerbrechen und nicht gleich in den meisten Fällen richtige Locks einsetzen? Als ob Multithreading nicht schon schwierig genug wäre ;) ... |
Re: Interlocked* mit Operator Überladung
Zitat:
94 ms - Inc (nicht threadsave) 281 ms - LOCK 359 ms - InterlockedExchangeAdd 1344 ms - EnterCriticalSection 1438 ms - TCriticalSection
Delphi-Quellcode:
uses Windows, SyncObjs;
type TInteger = record private Value: Integer; public procedure Add(i: Integer); end; TLockedInteger = record private Value: Integer; public procedure Add(i: Integer); end; TInterlockedInteger = record private Value: Integer; public procedure Add(i: Integer); end; TRTLCriticalSectionInteger = record private Value: Integer; Lock: TRTLCriticalSection; public procedure Init; procedure Finalize; procedure Add(i: Integer); end; TCriticalSectionInteger = record private Value: Integer; Lock: TCriticalSection; public procedure Init; procedure Finalize; procedure Add(i: Integer); end; procedure TInteger.Add(i: Integer); begin Inc(Value, i); end; procedure TLockedInteger.Add(i: Integer); asm lock add [eax], edx end; procedure TInterlockedInteger.Add(i: Integer); begin InterlockedExchangeAdd(Value, i); end; procedure TRTLCriticalSectionInteger.Init; begin InitializeCriticalSection(Lock); end; procedure TRTLCriticalSectionInteger.Finalize; begin DeleteCriticalSection(Lock); end; procedure TRTLCriticalSectionInteger.Add(i: Integer); begin EnterCriticalSection(Lock); try Inc(Value, i); finally LeaveCriticalSection(Lock); end; end; procedure TCriticalSectionInteger.Init; begin Lock := TCriticalSection.Create; end; procedure TCriticalSectionInteger.Finalize; begin Lock.Free; end; procedure TCriticalSectionInteger.Add(i: Integer); begin Lock.Enter; try Inc(Value, i); finally Lock.Leave; end; end; procedure TForm2.FormCreate(Sender: TObject); var C: LongWord; L, k: Integer; I: TInteger; LI: TLockedInteger; II: TInterlockedInteger; RCSI: TRTLCriticalSectionInteger; CSI: TCriticalSectionInteger; begin // cpu spin up for L := 0 to 100000000 do I.Add(10); C := GetTickCount; for L := 0 to 30000000 do I.Add(10); C := GetTickCount - C; Memo1.Lines.Add(IntToStr(C)); C := GetTickCount; for L := 0 to 30000000 do LI.Add(10); C := GetTickCount - C; Memo1.Lines.Add(IntToStr(C)); C := GetTickCount; for L := 0 to 30000000 do II.Add(10); C := GetTickCount - C; Memo1.Lines.Add(IntToStr(C)); C := GetTickCount; RCSI.Init; Try for L := 0 to 30000000 do RCSI.Add(10); Finally RCSI.Finalize; End; C := GetTickCount - C; Memo1.Lines.Add(IntToStr(C)); C := GetTickCount; CSI.Init; Try for L := 0 to 30000000 do CSI.Add(10); Finally CSI.Finalize; End; C := GetTickCount - C; Memo1.Lines.Add(IntToStr(C)); end; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:16 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