AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Record threadsicher verwenden

Ein Thema von MechMac666 · begonnen am 15. Mär 2021 · letzter Beitrag vom 17. Mär 2021
Antwort Antwort
MechMac666

Registriert seit: 9. Nov 2008
95 Beiträge
 
#1

AW: Record threadsicher verwenden

  Alt 15. Mär 2021, 21:21
Also mit TSynQueue hat es super geklappt. Danke für den Tipp.

Aber ich suche noch etwas für meine Userliste.

Der Gedanke wäre eine TThreadlist welche folgendes verwaltet.
Delphi-Quellcode:
 type TUser=record
    ID:int64;
    UserName:string;
    LoginCount:integer;
 end;

Jedoch sind alle Infos die ich dazu gesehen habe mit Klassen oder Objekten gemacht.
Ich bekomme es gerade absolut nicht hin da ein Record einzufügen.
Mit einer Variablen welche auf den Record pointet klappt das einfügen.
Delphi-Quellcode:
var ptUser:^TUser;
...
List := Userlist.LockList;
List.Add(ptUser);
...
Wenn ich ptUser.UserName vorher etwas zuweise und dann über list[0] versuche das zurückzulesen, gibt es ne Schutzverletzung.
Naja, irgendwie klar, denn ptUser pointet ja nur auf den Typ.

Oder muss ich von TUser ein Array erstellen und dessen Elemente der Threadlist zuweisen?


EDIT
Habe noch etwas gefunden wonach ich zunächst "new(ptUser)" aufrufen muss.
Mir ist aber noch nicht ganz klar, wo sich das erzeugte Objekt dann befindet und wie ich es erreiche.
Vor allem wie ich dann z.B. mit List[0] wieder auf den Typ TUser komme.

Geändert von MechMac666 (15. Mär 2021 um 21:41 Uhr)
  Mit Zitat antworten Zitat
mytbo

Registriert seit: 8. Jan 2007
483 Beiträge
 
#2

AW: Record threadsicher verwenden

  Alt 15. Mär 2021, 21:59
Aber ich suche noch etwas für meine Userliste.
Ich habe jetzt keine Möglichkeit zum Test, das sollte aber so funktionieren.
Delphi-Quellcode:
type
  TUser = record
    UserName: String;
    LoginCount: Integer;
  end;

  TUserID = Int64;
  TUserIDDynArray = array of TUserID;
  TUserDynArray = array of TUser;

FUserList := TSynDictionary.Create(TypeInfo(TUserIDDynArray), TypeInfo(TUserDynArray), False, {TimeoutSeconds=} 3600);
  
var
  user: TUser;
begin
  user.UserName := '';
  user.LoginCount := 2;
  FUserList.AddOrUpdate(userID, user);
Mit der Angabe TimeoutSeconds kannst du durch Aufruf von DeleteDeprecated() ältere Einträge rausschmeißen (hier 1 Stunde).

Bis bald...
Thomas
  Mit Zitat antworten Zitat
MechMac666

Registriert seit: 9. Nov 2008
95 Beiträge
 
#3

AW: Record threadsicher verwenden

  Alt 16. Mär 2021, 21:17
Ich probiere das gerade aus. Soweit passt das TSynDictionary sehr gut in das Konzept.
Allerdings bin ich nun bei meiner Broadcastliste hängen geblieben, welche ich im Zuge der Umstrukturierung auch ändern sollte.

Der Plan war/ist ein Array welches die ID's der eingeloggten User beinhaltet und nur bei Login/Logoff aktivität geupdatet wird.
Es wird für jede ausgehende Nachricht verwendet.
Der Zugriff darauf muss also auch threadsicher sein.

var logged_users:THttpServerConnectionIDDynArray;
Falls ich das Array nicht threadsicher führen kann, besteht die Möglichkeit sie aus dem TSynDictionary abzuleiten.
Aber es will mir nicht gefallen, für jede Nachricht diesen aufwändigen Prozess zu wiederholen.
Ich kann mir aus dem TSynDictionary die Values herausschreiben lassen um an die potenziellen Benutzer zu kommen, jedoch fehlt mit der Key dazu.
Oder anders ausgedrückt:
Delphi-Quellcode:
 type
  TUser = record
    UserName: String;
    LoginCount: Integer;
  end;

  TUserID = Int64;
  TUserIDDynArray = array of TUserID; //Key
  TUserDynArray = array of TUser; //Value
Ich würde dann jeden Key benötigen, wo der UserName<>'' ist.


Theoretisch könnte ich jetzt auch wieder ein TSynDictionary dafür missbrauchen indem ich key=Value setze.
Oder aber ich füge dem bestehenden TSynDictionary bei TUser noch die ID hinzu.
Nur das ist dann ja auch irgendwie doppelt gemoppelt wenn der Key nochmals in der Struktur der Value auftaucht.

Oder eben eine TThreradlist für das THttpServerConnectionIDDynArray. (Sofern ich es gebacken bekomme das darin abzubilden)
  Mit Zitat antworten Zitat
mytbo

Registriert seit: 8. Jan 2007
483 Beiträge
 
#4

AW: Record threadsicher verwenden

  Alt 16. Mär 2021, 22:36
Ich kann mir aus dem TSynDictionary die Values herausschreiben lassen um an die potenziellen Benutzer zu kommen, jedoch fehlt mit der Key dazu.
Ich verstehe dein Problem nicht ganz. Aber nach einem Value kannst du wie folgt suchen:
Delphi-Quellcode:
var
  user: TUser;
  userID: TUserID;
begin
  userID := 5;
  user.UserName := 'Klaus';
  user.LoginCount := 3;
  FUserList.AddOrUpdate(userID, user);
  
  userID := 0;
  FUserList.FindKeyFromValue(user, userID); // userID = 5
Oder du nutzt die Funktion FUserList.ForEach().

Bis bald...
Thomas
  Mit Zitat antworten Zitat
MechMac666

Registriert seit: 9. Nov 2008
95 Beiträge
 
#5

AW: Record threadsicher verwenden

  Alt 16. Mär 2021, 23:01
Zitat:
Ich verstehe dein Problem nicht ganz.
Naja, ich würde mal behaupten das es weniger systemlastig ist eine Nachricht mit einem bereits fertig verfügbaren Empfängerarray zu broadcasten,
anstatt ein solches Array für JEDE Nachricht aus dem TSynDictionary neu aufzustellen.

Im Grunde resultiert das zweite Problem aus dem ersten:
Nutze ich das
var logged_users:THttpServerConnectionIDDynArray; dann ist es nicht threadsicher. Aber es ist "sofort" verfügbar.
Wenn ich das Array für jede Nachricht aus dem TSynDictionary zusammen baue, fürchte ich eine hohe Systemlast.
Und zusätzlich habe ich dann das folgende Problem:


Die Nachricht darf nur an User versendet werden, dessen Name hinterlegt ist.
Somit müsste ich das ganze TSynDictionary durchgehen und prüfen, ob da ein Username drin steht.
Und wenn, dann brauche ich den Key dazu.

Deswegen wird mir das nicht helfen:
FUserList.FindKeyFromValue(user, userID); // userID = 5 Der User 'Klaus' aus dem Beispiel kann ja von verschiedenen Endgeräten eingeloggt sein. Er hat demnach verschiedene ID's.




Mein erster Ansatz war:
Delphi-Quellcode:
  FUserList.CopyValues(users);
  for I := Low(users) to High(users) do
  if (users[i].UserName<>'') then //Alle eingeloggten User
  begin
  //Und hier komme ich nicht an die ID, da sie der KEY ist und ich keinen Bezug dazu habe
  end;

Geändert von MechMac666 (16. Mär 2021 um 23:08 Uhr)
  Mit Zitat antworten Zitat
mytbo

Registriert seit: 8. Jan 2007
483 Beiträge
 
#6

AW: Record threadsicher verwenden

  Alt 17. Mär 2021, 11:05
Ich antworte allgemein. Wenn du noch kein gutes Gefühl für die richtige Architektur hast, probiere zuerst die einfachste Lösung aus: "make it work, then make it fast".

TDynArray/TDynArrayHashed sind nur die "mächtige Verwaltung" eines array of x. Values und Keys in einem TSynDictionary sind TDynArray/TDynArrayHashed Arrays. Wenn du den Array-Index des Values hast, hast du auch den Array-Index des Keys. TSynDictionary ermöglicht den direkten Zugriff auf die Values. Count gibt den Füllstand zurück. Mit Values.ElemPtr(idx)^ greifst du zu. Und Threadsafe wird es mit einem Lock/UnLock um alles. Die Ausführungszeit dürfte sich im Bereich us Sekunden bewegen. Du kannst die benötigten IDs damit zusammensammeln.

Wenn dich die genaue Zeit interessiert:
Delphi-Quellcode:
var
  Timer: TPrecisionTimer;
begin
  Timer.Start;
  ...
  ShowMessage(Format('Total time: %s', [Timer.Stop]));
end;
Bis bald...
Thomas
  Mit Zitat antworten Zitat
Antwort Antwort


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 10:43 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