AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein TInterlocked außerhalb eines TThreads?
Thema durchsuchen
Ansicht
Themen-Optionen

TInterlocked außerhalb eines TThreads?

Ein Thema von SneakyBagels · begonnen am 2. Jul 2017 · letzter Beitrag vom 3. Jul 2017
Antwort Antwort
Seite 2 von 2     12   
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#11

AW: TInterlocked außerhalb eines TThreads?

  Alt 2. Jul 2017, 17:30
Wenn die Threads sauber implementiert sind, macht es keinen Sinn ohne konkreten Anlass einfach irgendetwas zu locken.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
SneakyBagels
(Gast)

n/a Beiträge
 
#12

AW: TInterlocked außerhalb eines TThreads?

  Alt 2. Jul 2017, 17:33
Meine Threads haben alle schreibenden Zugriff auf ein paar in einem Record befindlichen Variablen.

Ich könnte das auch ohne locken machen nur das wäre echt eine super dämliche Lösung:
jeder Thread schreibt in seine eigenen, lokalen Variablen und erst bein Thread-Destroy schreibe ich den lokalen Wert in ein globale Variable.
Somit hätte ich statt einem ständigem Locken nur noch einmal Locken.
Das ist aber böse, hässlich und einfach nicht gut also mache ich den Text mal grau
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#13

AW: TInterlocked außerhalb eines TThreads?

  Alt 2. Jul 2017, 19:39
Das heißt jeder Thread aktualisiert gegebenenfalls mehrere Variablen hintereinander?
Dann würde ich eine Klasse daraus machen und schlicht mit TMonitor.Enter...TMonitor.Exit arbeiten.

Oder geht es immer nur um einzelne Werte?
Dann würde ich ebenfalls eine Klasse daraus machen (geht aber auch als Record) und Setter benutzen (inline deklarieren wegen der Performance), die sich dann um die Locks kümmern.
Die können das dann auch mit TInterlocked machen, aber du musst das nicht überall im Quelltext machen.

Beides sind saubere Lösungen.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
SneakyBagels
(Gast)

n/a Beiträge
 
#14

AW: TInterlocked außerhalb eines TThreads?

  Alt 2. Jul 2017, 20:01
Zitat:
Dann würde ich ebenfalls eine Klasse daraus machen (geht aber auch als Record) und Setter benutzen (inline deklarieren wegen der Performance), die sich dann um die Locks kümmern.
Ist mir ehrlich gesagt zuviel Aufwand mit Klassen und dann den Settern.

Aktuell ist es schlicht so:
es existiert ein Record und auf die einzelnen Werte greife ich zu une modifiziere sie mit TInterLocked.
Und damit ich nur an einer Stelle im Code die Variable selber habe ist es so gelößt


Delphi-Quellcode:

// unit _globals.pas
type
 TTestRecord = packed record
  test, hallo, huhu: Int64;
 end;
var aTestRecord: TTestRecord;

// Unit _enums.pas
type
 TTestEnum = (test, hallo, huhu);

// unit log_utils.pas
procedure test(const aTestEnum: TTestEnum; iIncrement: Integer = 1);
begin
 case aTestEnum do
  TTestEnum.test:
   TInterLocked.Add(aTestRecord.test, iIncrement);

  TTestEnum.hallo:
   TInterLocked.Add(aTestRecord.hallo, iIncrement);

  TTestEnum.huhu:
   TInterLocked.Add(aTestRecord.huhu, iIncrement);
 end;
end;

// unit... überall da wo ich es brauche
test(TTestEnum.hallo, 5);
test(TTestEnum.huhu);
Wenn es auf einfache Art und Weise besser geht (wovon ich ausgehe) dann nehme ich diese Kritik gerne an!

Geändert von SneakyBagels ( 2. Jul 2017 um 20:59 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#15

AW: TInterlocked außerhalb eines TThreads?

  Alt 2. Jul 2017, 23:17
Sehr einfach:
Delphi-Quellcode:
// unit _globals.pas
type
  TTest = class
  private
    class var FTest, FHallo, FHuhu: Int64;
  public
    class procedure IncTest(const AValue: Int64 = 1); inline;
    class procedure IncHallo(const AValue: Int64 = 1); inline;
    class procedure IncHuhu(const AValue: Int64 = 1); inline;
    class property Test: Int64 read FTest;
    class property Hallo: Int64 read FHallo;
    class property Huhu: Int64 read FHuhu;
  end;

  { TTest }

class procedure TTest.IncHallo(const AValue: Int64 = 1);
begin
  TInterLocked.Add(FHallo, AValue);
end;

class procedure TTest.IncHuhu(const AValue: Int64 = 1);
begin
  TInterLocked.Add(FHuhu, AValue);
end;

class procedure TTest.IncTest(const AValue: Int64 = 1);
begin
  TInterLocked.Add(FTest, AValue);
end;

  // unit... überall da wo ich es brauche
procedure Test1;
begin
  TTest.IncHallo(5);
  TTest.IncHuhu;

// lesen:
  ShowMessage(IntToStr(TTest.Hallo));
end;
Deine Lösung empfinde ich als mehr Aufwand als diese (zusätzliche Variable, zusätzliches Set, zusätzliches case, ...). Und langsamer ist deine durch die zusätzliche Fallunterscheidung und das fehlende inline auch. Dazu kommt noch, dass die Funktionalität so auf drei Units verteilt ist.

Zusätzlicher Vorteil:
Von außen gibt es durch die Properties keinen schreibenden Zugriff mehr auf die Felder, trotzdem kann lesend direkt auf die Felder zugegriffen werden (da es keinen Getter gibt, werden direkt die Werte verwendet).

// EDIT:
Nebenbei, falls die Unitnamen echt sind:
Unterstriche in Unitnamen und Bezeichnern sind in Delphi unüblich. In Delphi ist CamelCase üblich und für Unitnamen auch Punkte. (Empfinde ich auch als deutlich besser lesbar.)
Bei uns würden die Units z.B. heißen (wenn es allgemeine Units für mehrere Projekte sind, daher Common):
Common.Utils.Logging.pas, Common.Types.Logging.pas, ... (Im Unterverzeichnis common\utils bzw. common\types)
Und so allgemeine Namen wie _globals oder so würde es bei uns nicht geben, da das nichts über die Funktion aussagt. Die Klasse hieße bei uns dann auch z.B. TLogging und wäre die einzige in der Unit.
Auf die Weise werden auch die Units nicht so groß und übersichtlich und man findet auch direkt die Units zu den Klassen.
Sebastian Jänicke
AppCentral

Geändert von jaenicke ( 2. Jul 2017 um 23:29 Uhr)
  Mit Zitat antworten Zitat
SneakyBagels
(Gast)

n/a Beiträge
 
#16

AW: TInterlocked außerhalb eines TThreads?

  Alt 2. Jul 2017, 23:23
Ich gucke mir das mal ganz genau an um es auch zu verstehen.
Aktuell verwende ich solche Klassen-Konstrukte häufig. Record statt Class und statt inline verwende ich aber static (weil ich es damals so gefunden habe).

Aber ich gucke mal wie ich das bei mir umgesetzt bekomme.
Ich habe schon gelesen, dass inline wohl für kleine Prozeduren/Funktionen von Vorteil sein soll.
Wie sieht das denn mit Prozeduren/Funktionen aus, die 200+ Zeilen lang sind?

Geändert von SneakyBagels ( 2. Jul 2017 um 23:30 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von jaenicke
jaenicke

Registriert seit: 10. Jun 2003
Ort: Berlin
9.648 Beiträge
 
Delphi 11 Alexandria
 
#17

AW: TInterlocked außerhalb eines TThreads?

  Alt 3. Jul 2017, 00:19
statt inline verwende ich aber static (weil ich es damals so gefunden habe)
Das eine hat mit dem anderen nichts zu tun außer dass es beides der Performance dienlich ist. Mit inline sorgst du dafür, dass statt des Assemblerbefehls Call mit Parameterübergabe usw. der Quelltext der aufgerufenen Funktion direkt an der Stelle des Aufrufs eingebaut wird.
Mit static gibt es kleinste Optimierungen durch die Tatsache, dass EAX nicht als Self-Pointer benötigt wird. Das sind aber nur einzelne Assemblerbefehle, die wegfallen.

Bei größeren Funktionen bringt inline nicht mehr so viel, denn wenn eine Funktion z.B. nur 20 Assemblerbefehle enthält wie in diesem Fall bei IncTest usw. macht es schon einen Unterschied, ob noch 10 für den Methodenaufruf hinzukommen. Hat die Funktion 200 Zeilen Pascalcode (schon sehr viel übrigens, da schlägt jede Metrikanalyse für Quelltext Alarm), relativiert sich das, weil der Code für den Aufruf im Verhältnis zum Methodeninhalt sehr klein ist.
Sebastian Jänicke
AppCentral
  Mit Zitat antworten Zitat
SneakyBagels
(Gast)

n/a Beiträge
 
#18

AW: TInterlocked außerhalb eines TThreads?

  Alt 3. Jul 2017, 00:41
Wieso gibt es hier eigentlich noch keinen "Danke"-Button?

Zu deinem Code oben.
Ich habe es jetzt erst einmal vorläufig so gemacht:
Delphi-Quellcode:
// unit _globals.pas (vorläufig bleibt es bis Zeit habe und richtig umbaue)
type
 TTestRecord = packed record
  test, hallo, huhu: Int64;
 end;
var aTestRecord: TTestRecord;

// Unit _enums.pas (das ist weg)
// type
// TTestEnum = (test, hallo, huhu);

// unit log_utils.pas
procedure test(iTarget: Int64; iIncrement: Integer = 1);
begin
 TInterLocked.Add(iTarget, iIncrement);
end;

// unit... überall da wo ich es brauche
test(aTestRecord.hallo, 5);
test(aTestRecord.huhu);
Ist das trotzdem schon besser als vorher?

Geändert von SneakyBagels ( 3. Jul 2017 um 01:01 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


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 12:29 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