AGB  ·  Datenschutz  ·  Impressum  







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

TIniFile und Terminal-Server

Ein Thema von hoika · begonnen am 14. Nov 2013 · letzter Beitrag vom 15. Nov 2013
Antwort Antwort
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.270 Beiträge
 
Delphi 10.4 Sydney
 
#1

TIniFile und Terminal-Server

  Alt 14. Nov 2013, 16:22
Hallo #,

nicht hauen, ist halt eine "legacy app".
Ich habe hier ein Programm,
was in eine zentrale Ini-Datei einige Einstellungen schreibt.
Die Datei liegt an einer zentral zugänglichen Stelle (z.B. C:\Data).

Jetzt soll dieses Programm auf einem Terminal-Server (TS) laufen.
Wenn jetzt 10 Nutzer das Programm parallel starten und "wild in der Ini rumschreiben",
kann das zu Problemen führen ?

Oder anders gesagt:
Synchronisiert der TS Ini-Zugriffe, vor allem beim Schreiben ?


Bitte keine Sprüche, wie "das macht man nicht mit Inis", "falscher Pfad".
Ist alles bekannt, wird bei Gelegenheit auch umgestellt,
geht aber nicht von heute auf gestern.


Danke

Heiko
Heiko
  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
 
#2

AW: TIniFile und Terminal-Server

  Alt 14. Nov 2013, 16:30
Dafür nimmt man einen Mutex.

Aber das Global\<MutexName> nicht vergessen
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 himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.139 Beiträge
 
Delphi 12 Athens
 
#3

AW: TIniFile und Terminal-Server

  Alt 14. Nov 2013, 16:40
TIniFile synchronisiert rein garnichts, ABER

Jeder einzelne Schreibzugriff auf die INI, also jedes einzelne WriteInteger usw. liest diese Datei erneut aus, händert den Wert und schreibt die Datei sofort zurück.



Globale Einstellungen sollten aber auch global sein und sowas sollte sich eigentlich selten ändern.
Einstellungen für die einzelnen Instanzen sollten besser auch in einzelnen Dateien landen und schon kommt sich da nix mehr in die Quere.

Ansonsten mußt du schon selber die Schreibzugriffe synchronisieren, bzw. gleichzeitige Zugriffe verhindern.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG

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

AW: TIniFile und Terminal-Server

  Alt 14. Nov 2013, 17:48
Wenn du häufig aus der INI-Datei liest, dann kannst du dir die Reader-Writer-Synchronisation anschauen.
Die lässt sich auch mit globalen Synchronisierungsmitteln nachbauen.
  Mit Zitat antworten Zitat
hoika

Registriert seit: 5. Jul 2006
Ort: Magdeburg
8.270 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: TIniFile und Terminal-Server

  Alt 15. Nov 2013, 10:36
Hallo,

danke für die Antworten.

Ich habe die App mal auf einem W2003-Server parallel laufen lassen,
es gab bei den Inis keine Probleme.
Vielleicht bin ich zu langsam ?

Das mit dem Mutex klingt gut ...


Heiko
Heiko
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.139 Beiträge
 
Delphi 12 Athens
 
#6

AW: TIniFile und Terminal-Server

  Alt 15. Nov 2013, 10:57
Da hier jeder einzelne Zugriff auf die Werte einen Schreibzugriff darstellen und nicht alles vom Create bis zum Free einen gemeinsamen Zugriff darstellt (am Anfang auslesen und erst am Ende alles speichern),

Gehen die Zugriffe recht schnell, aber wenn z.B. zwei WriteInteger fast zur selben Zeit ausgeführt werden

Code:
Programm 1 liest die Datei ein und verändert im Arbeitsspeicher den Inhalt für einen Wert
Programm 2 liest die Datei ein und verändert im Arbeitsspeicher den Inhalt für einen Wert
Programm 1 speichert die Änderungen
Programm 2 speichert die Änderungen
Dann geht natürlich die Ändeung von 2 verloren.

Ich weiß auch nicht wie die Sharing-Rechte bei Lese und Schreibzugriffen von Microsoft geregelt sind, dementsprechend kann es natürlich auch zu einem "Zugriff verweigert" kommen, wenn gleichzeitig auf die Datei zugegriffen wird.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu
Online

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.139 Beiträge
 
Delphi 12 Athens
 
#7

AW: TIniFile und Terminal-Server

  Alt 15. Nov 2013, 11:23
Einfach mal mehrere Programme/Threads mit diesem Code ausführen und die 10 Minuten warten, ob es knallt.
Delphi-Quellcode:
with TIniFile.Create('text.ini') do
  try
    Ident := 'Ident' + IntToStr(GetCurrentThreadId);
    Start := GetTickCount;
    Errors := 0;
    Counter := 0;
    while GetTickCount - Start < 1000*60*10 do begin // 10 Minuten testen
      WriteInteger('Section', Ident, Counter);
      Value := ReadInteger('Section', Ident, -1);
      if Value <> Counter then
        Inc(Errors);
      Inc(Counter);
    end;
    if Errors <> 0 then
      raise Exception.CreateFmt('%d Errors', [Errors]);
  finally
    Free;
  end;
oder
Delphi-Quellcode:
with TIniFile.Create('text.ini') do
  try
    Ident := 'Ident' + IntToStr(GetCurrentThreadId);
    Start := GetTickCount;
    Value := ReadInteger('Section', Ident, 0); // richtiger Startwert, falls es diese Datei schon gibt.
    Counter := Value;
    while GetTickCount - Start < 1000*60*10 do begin // 10 Minuten testen
      Value := ReadInteger('Section', Ident, 0);
      WriteInteger('Section', Ident, Value + 1);
      Inc(Counter);
      Sleep(Random(100));
    end;
    if Value <> Counter then
      raise Exception.CreateFmt('Error (%d <> %d)', [Value, Counter]);
  finally
    Free;
  end;
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  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
 
#8

AW: TIniFile und Terminal-Server

  Alt 15. Nov 2013, 11:49
Und dann kannst du das mal mit dieser von TIniFile abgeleiteten Klasse versuchen
Bei jedem Zugriff auf die Datei wird erst der Mutex betreten und danach wieder verlassen.
Delphi-Quellcode:
unit MutexIniFile;

interface

uses
  System.Classes,
  System.SyncObjs,
  System.SysUtils,
  System.IniFiles;

type
  TMutexIniFile = class( TIniFile )
  private
    FMutex : TMutex;
    FUpdateLock : Integer;
  protected
    function GetMutexName : string; virtual;
  public
    constructor Create( const FileName : string );
    destructor Destroy; override;

    function ReadString(const Section, Ident, Default: string): string; override;
    procedure WriteString(const Section, Ident, Value: String); override;
    procedure ReadSection(const Section: string; Strings: TStrings); override;
    procedure ReadSections(Strings: TStrings); override;
    procedure ReadSectionValues(const Section: string; Strings: TStrings); override;
    procedure EraseSection(const Section: string); override;
    procedure DeleteKey(const Section, Ident: String); override;
    procedure UpdateFile; override;

    procedure BeginUpdate;
    procedure EndUpdate;
  end;

implementation

{ TMutexIniFile }

procedure TMutexIniFile.BeginUpdate;
begin
  if FUpdateLock = 0
  then
    FMutex.Acquire;
  Inc( FUpdateLock );
end;

constructor TMutexIniFile.Create( const FileName : string );
begin
  inherited;
  FMutex := TMutex.Create( nil, False, 'Global\' + GetMutexName );
end;

procedure TMutexIniFile.DeleteKey( const Section, Ident : string );
begin
  BeginUpdate;
  try
    inherited;
  finally
    EndUpdate;
  end;
end;

destructor TMutexIniFile.Destroy;
begin
  while FUpdateLock > 0 do
    EndUpdate;

  FMutex.Free;
  inherited;
end;

procedure TMutexIniFile.EndUpdate;
begin
  Dec( FUpdateLock );
  if FUpdateLock = 0
  then
    FMutex.Release;
end;

procedure TMutexIniFile.EraseSection( const Section : string );
begin
  BeginUpdate;
  try
    inherited;
  finally
    EndUpdate;
  end;
end;

function TMutexIniFile.GetMutexName : string;
  function HashOf( const Key : string ) : Cardinal;
  var
    I : Integer;
  begin
    Result := 0;

    for I := 0 to Key.Length - 1 do
      begin
        Result := ( ( Result shl 2 ) or ( Result shr ( SizeOf( Result ) * 8 - 2 ) ) ) xor Ord( Key.Chars[I] );
      end;
  end;

begin
  Result := Format( 'inifile_%.8x', [HashOf( FileName )] );
end;

procedure TMutexIniFile.ReadSection( const Section : string; Strings : TStrings );
begin
  BeginUpdate;
  try
    inherited;
  finally
    EndUpdate;
  end;
end;

procedure TMutexIniFile.ReadSections( Strings : TStrings );
begin
  BeginUpdate;
  try
    inherited ReadSections( Strings );
  finally
    EndUpdate;
  end;
end;

procedure TMutexIniFile.ReadSectionValues( const Section : string; Strings : TStrings );
begin
  BeginUpdate;
  try
    inherited;
  finally
    EndUpdate;
  end;
end;

function TMutexIniFile.ReadString( const Section, Ident, Default : string ) : string;
begin
  BeginUpdate;
  try
    Result := inherited;
  finally
    EndUpdate;
  end;
end;

procedure TMutexIniFile.UpdateFile;
begin
  BeginUpdate;
  try
    inherited;
  finally
    EndUpdate;
  end;
end;

procedure TMutexIniFile.WriteString( const Section, Ident, Value : string );
begin
  BeginUpdate;
  try
    inherited;
  finally
    EndUpdate;
  end;
end;

end.
Die Hash-Routine für den Dateinamen ist eine sehr einfache und kann bei Bedarf auch gewechselt werden.
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
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 18:13 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