AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi TInterlocked.Exchange bei Zugriff eines nur lesenden Threads?
Thema durchsuchen
Ansicht
Themen-Optionen

TInterlocked.Exchange bei Zugriff eines nur lesenden Threads?

Ein Thema von Zacherl · begonnen am 16. Mär 2015 · letzter Beitrag vom 20. Mär 2015
Antwort Antwort
Seite 2 von 3     12 3      
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#11

AW: TInterlocked.Exchange bei Zugriff eines nur lesenden Threads?

  Alt 16. Mär 2015, 21:54
So wohl nicht, aber das hier:

Delphi-Quellcode:
type
  TRec = packed record
    B: Byte;
    A: Integer;
  end;
führt dazu, daß A eher nicht auf einer der CPU genehmen Speichergrenze liegt und die damit zwei Zyklen zum Schreiben braucht. Zwischen diesen beiden Zyklen kann aber ein Lesezugriff (ebenfalls zwei Zyklen) erfolgen. Das hängt aber auch konkret von der verwendeten CPU ab.
Das ist ärgerlich. Sollte sowas nicht irgendwo in der x86-64 ISA spezifiziert sein? Ich erwarte ja schon irgendwie konstantes Verhalten auf allen x86 CPUs, wenn ich ein MOV ausführe.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.034 Beiträge
 
Delphi 12 Athens
 
#12

AW: TInterlocked.Exchange bei Zugriff eines nur lesenden Threads?

  Alt 16. Mär 2015, 22:45
Das ist ärgerlich. Sollte sowas nicht irgendwo in der x86-64 ISA spezifiziert sein? Ich erwarte ja schon irgendwie konstantes Verhalten auf allen x86 CPUs, wenn ich ein MOV ausführe.
Für x86 CPUs ist das auch einheitlich. Lediglich das Modulo der Startadresse für einen Ein-Zyklus-Zugriff ist zwischen 32- und 64-Bit unterschiedlich. Es gibt aber ja auch noch andere CPUs.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Benutzerbild von Mavarik
Mavarik

Registriert seit: 9. Feb 2006
Ort: Stolberg (Rhld)
4.130 Beiträge
 
Delphi 10.3 Rio
 
#13

AW: TInterlocked.Exchange bei Zugriff eines nur lesenden Threads?

  Alt 17. Mär 2015, 11:31
Das ist eine Frage der Ausrichtung...

Wenn Du mit {$A1} arbeitest ist es nicht sicher...

Wie ich gelesen haben übrigens auch nicht zu 100% bei einem Interger. Also lieber ein Interlock oder CS

Mavarik
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#14

AW: TInterlocked.Exchange bei Zugriff eines nur lesenden Threads?

  Alt 17. Mär 2015, 12:39
Dann hat man auch einen Erfahrungswert und wird noch viel ruhiger
Erfahrungswerte sind bei Speichersemantik kritisch zu sehen. Fehler sind meisten ziemlich subtil, treten selten auf und sind schlecht reproduzierbar.
Es ist in 99% der Fälle besser die entsprechenden Bibliotheksfunktionen und Datentypen (richtig ausgerichtet) für atomare Zugriffe zu benutzen.

Und es nicht nur der Speicher selbst, auch der Compiler und Out-Of-Order-Execution kann dir reinpfuschen:
Delphi-Quellcode:
// Thread 1
ptr = Class.create():
ptr.value = 1337;
global_ptr = ptr;
Delphi-Quellcode:
// Thread 2
write(global_ptr.foo); // 1337?
Der Compiler weiß nicht, dass global_ptr von mehreren Threads benutzt wird und ordnet das wegen Optimierung so um (oder der Prozessor macht das; warum auch nicht):
Delphi-Quellcode:
// Thread 1
ptr = Class.create():
global_ptr = ptr;
ptr.value = 1337;
Den Fehler finde erst mal

Die Bibliotheksfunktionen sind entweder dem Compiler bekannt oder zumindest undurchsichtig, so dass er solche Spielchen lässt. Intern wird da sichergestellt, dass der Prozessor nichts umordnet (Memory Barriers oder andere Tricks).


Wenn es nur um Sachen geht, die schiefgehen können (z.B. Integer für Fortschrittsanzeige auslesen) mag das alles gut gehen. Alles darüber hinaus sollte man vorsichtig angehen.

Geändert von BUG (17. Mär 2015 um 12:43 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#15

AW: TInterlocked.Exchange bei Zugriff eines nur lesenden Threads?

  Alt 17. Mär 2015, 12:52
Verdammt, dann habe ich wohl etwas Arbeit vor mir

Wie gehe ich am besten bei Enumtypen vor? Alles mit $Z4 deklarieren und dann immer die Integer Variante von InterlockedExchange benutzen dürfte die sicherste Methode sein oder? Gibt es analog hierzu auch eine Möglichkeit "ranged types" auf eine bestimmte Größe zu forcen?
Delphi-Quellcode:
type
  TRangedType = 0..1023;
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#16

AW: TInterlocked.Exchange bei Zugriff eines nur lesenden Threads?

  Alt 17. Mär 2015, 14:05
Verdammt, dann habe ich wohl etwas Arbeit vor mir
Häh, wieso das denn? Pack die Felder in eine Klasse, gibt der Klasse ein Synchro-Mechanismus an die Hand und dann geht es ab.
Delphi-Quellcode:
TFoo = class
private
  FCS : TCriticalSection;
  FValue : string;
  function GetValue : string;
  procedure SetValue(const Value : string) : string;
public
  constructor Create;
  destructor Destroy; override;

  property Value : string read GetValue write SetValue;
end;

constructor TFoo.Create;
begin
  inherited;
  FCS := TCriticalSection.Create;
end;

destructor TFoo.Destroy;
begin
  FreeAndNil( FCS );
  inherited;
end;

function GetValue : string;
begin
  FCS.Enter;
  try
    Result := FValue;
  finally
    FCS.Leave;
  end;
end;

procedure SetValue(const Value : string) : string;
begin
  FCS.Enter;
  try
    FValue := Value;
  finally
    FCS.Leave;
  end;
end;
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#17

AW: TInterlocked.Exchange bei Zugriff eines nur lesenden Threads?

  Alt 17. Mär 2015, 14:23
Klar, das ist sicherlich ein brauchbarer Ansatz (den ich auch partiell schon implementiert hatte). Allerdings habe ich gelesen, dass Critical Sections nicht umbedingt super performant sind. Zumindest bei den Werten, die alle paar Milisekunden aktualisiert werden, wollte ich lieber die Interlocked Funktionen verwenden.

Kann man bezüglich der "ranged types" was machen, oder bin ich hier gezwungen Critical Sections zu benutzen?
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#18

AW: TInterlocked.Exchange bei Zugriff eines nur lesenden Threads?

  Alt 17. Mär 2015, 14:30
Klar, das ist sicherlich ein brauchbarer Ansatz (den ich auch partiell schon implementiert hatte). Allerdings habe ich gelesen, dass Critical Sections nicht umbedingt super performant sind. Zumindest bei den Werten, die alle paar Milisekunden aktualisiert werden, wollte ich lieber die Interlocked Funktionen verwenden.

Kann man bezüglich der "ranged types" was machen, oder bin ich hier gezwungen Critical Sections zu benutzen?
Du brauchst einen Synchro-Mechanismus (den man - wie hier exemplarisch gezeigt - mit einer CriticalSection machen kann, oder mit TMonitor , oder, oder, oder, oder, ..... )

Welchen, das hängt eben davon ab, was da atomar ablaufen soll/muss. Ein TInterlocked geht eben nur für einen Wert und eben nur für bestimmte Typen
Delphi-Referenz durchsuchenSystem.SyncObjs.TInterlocked
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo (17. Mär 2015 um 14:38 Uhr)
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.111 Beiträge
 
Delphi 10 Seattle Enterprise
 
#19

AW: TInterlocked.Exchange bei Zugriff eines nur lesenden Threads?

  Alt 17. Mär 2015, 15:08
Und die Synchronisationsobjekte (unter System.SyncObjs) leiten sich doch alle von einer gemeinsamen Oberklasse ab. Wenn du später eine die TCriticalSection gegen etwas anderes austauschen willst, ist das nur eine Sache- Ich hätte Sir Rufos Ansatz noch um eine Typdefinition erweitert:

Delphi-Quellcode:
TFoo = class
protected type
   TSyncObj = TCriticalSection;
private
   FCS : TSyncObj;
   FValue : string;
   function GetValue : string;
   procedure SetValue(const Value : string) : string;
public
   constructor Create;
   destructor Destroy; override;

   property Value : string read GetValue write SetValue;
end;
Dann kannst du später alles in einer Zeile austauschen.
  Mit Zitat antworten Zitat
Benutzerbild von Zacherl
Zacherl

Registriert seit: 3. Sep 2004
4.629 Beiträge
 
Delphi 10.2 Tokyo Starter
 
#20

AW: TInterlocked.Exchange bei Zugriff eines nur lesenden Threads?

  Alt 17. Mär 2015, 15:33
Ein TInterlocked geht eben nur für einen Wert und eben nur für bestimmte Typen
Delphi-Referenz durchsuchenSystem.SyncObjs.TInterlocked
Ja das ist klar. Sind im Prinzip alles triviale Typen, die ich syncen will (1, 2, 4 und 8 Byte). Habe mir über eine Helper Class bereits noch ein paar Funktionen für UInt32 und UInt64 hinzugefügt, da es die unsigned Varianten leider nicht standardmäßig gibt (dank des var Parameters kann man auch nicht einfach casten).

Bin momentan am sichten, auf welche Felder in welcher Form von wo aus zugegriffen wird.

Momentan habe ich vier verschiedene Modi:
  1. Read im internen Thread UND externen Threads, Write nur im internen Thread
    • Benötigte eine gesyncte Read Funktion, eine ungesyncte Read Funktion (für den internen Thread aus Performancegründen) und eine gesyncte Write Funktion
  2. Read im internen Thread UND externen Threads, Write im internen UND externen Threads
    • Benötigte eine gesyncte Read Funktion und eine gesyncte Write Funktion
  3. Read im internen Thread UND externen Threads, Write einmal im Konstruktor bevor irgendein Zugriff von irgendwo möglich ist
    • Muss nicht synchronisiert werden
  4. Read nur in externen Threads, Write einmal im Konstruktor bevor irgendein Zugriff von irgendwo möglich ist
    • Muss nicht synchronisiert werden

Hoffe ich habe da grade keine Logikfehler eingebaut.

Und die Synchronisationsobjekte (unter System.SyncObjs) leiten sich doch alle von einer gemeinsamen Oberklasse ab. Wenn du später eine die TCriticalSection gegen etwas anderes austauschen willst, ist das nur eine Sache- Ich hätte Sir Rufos Ansatz noch um eine Typdefinition erweitert
Die Interlocked Funktionen sind allerdings nicht in der selben Form in einem SyncObject gekapselt. Austauschen werde ich die Synchronisierungsobjekte allerdings wohl eh niemals.
Projekte:
- GitHub (Profil, zyantific)
- zYan Disassembler Engine ( Zydis Online, Zydis GitHub)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 3     12 3      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:09 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz