Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   stringzugriff - wie könnte ich das regeln (https://www.delphipraxis.net/59716-stringzugriff-wie-koennte-ich-das-regeln.html)

meisteralex 27. Dez 2005 18:10


stringzugriff - wie könnte ich das regeln
 
Ich hab folgendes Problem
Hab hier ein Programm was ereignisse logt, so z.b. wenn jemand die maus bewegt, wenn sich ein neues fenster öffnet etc.
das sieht so aus, dass die ereignisse in einen string geschrieben werden (var logstring:string).
wenn jetzt z.b. jemand die maus bewegt wird mit logstring := logstring + '|MBA|x,y|MBE|' diese aktion in den string geschrieben (MBA und MBE dienen dabei als Identifier).
Hinterher wird der String dann in eine Datei geschrieben, wenn er "voll genug" ist.
Mein Problem ist nur, dass wenn die Maus bewegt wird und gleichzeitig z.b ein neues Fenster erscheint, quasi gleichzeitig auf den String zu gegriffen wird.
Anstatt wie es richtig wäre " |NFA|Ich bin ein neues Fenster|NFE| |MBA|x,y|MBE| " steht dann schonmal im String " |NFA|Ich bin ein ne|MBA|x,y|MBE|ues Fenster|NFE|" was mir hinterher bei der Auswertung ja nix mehr bringt.
Wie kann ich es also verhinder, dass der string logstring erst von der einen Prozedur fetch_MB(); geändert wird und solange exclusiv dieser prozedur zur Verfügung steht. Jemand ne idee ?

alzaimar 27. Dez 2005 18:31

Re: stringzugriff - wie könnte ich das regeln
 
Solche parallelen Zugriffe must Du kapseln. Windows und damit Delphi bieten Dir diverse Werkzeuge zur Synchronisation. Wenn Du innerhalb eines Prozesses (nicht Thread) darauf zugreifst, reicht eine 'Critical Section'. Ansonsten, also wenn z.B. zwei Prozesse parallel auf etwas zugreifen müssen, dann muss man andere Mechanismen (z.B. Mutexe) verwenden.

Die Unit SyncObjs hält alle Delphi-Objekte bereit, um Dein Problem zu lösen.
Delphi-Quellcode:
Uses ... SyncObjs...;

Var
  MyCS : TCriticalSection;

Procedure ThreadSafeAdd (Var aSrc : String; Const aString);
Begin
  MyCS.Enter;
  Try
    aSrc := aSrc + aString;
  Finally
    MyCS.Leave;
  End;
End;

Initialization
  MyCS := TCriticalSection.Create;
Finalization
  MyCS.Free;
End.
Natürlich sollte man sowas als Klasse 'TThreadSafeString' implementieren.

meisteralex 29. Dez 2005 12:10

Re: stringzugriff - wie könnte ich das regeln
 
hmm wie kann ich dennn testen ob es wirklich daran liegt
hab jetzt 3 timer auf einer form laufen , die alle 10ms den gleichen string bearbeiten,
hier treten jedoch sowohl mit als auch ohne den criticalselection code keine überschneidungen auf.
kann es vielleicht doch an was anderem liegen ?

marabu 29. Dez 2005 12:23

Re: stringzugriff - wie könnte ich das regeln
 
Wenn du das logging aus einem thread heraus machst, dann ist eine Synchronisierung notwendig. Wenn du aber den log string aus einem VCL event handler aufbaust, dann eher nicht, da deine Delphi Anwendung ohne dein Zutun keine Nebenläufigkeit aufweist.

Grüße vom marabu

alzaimar 29. Dez 2005 13:09

Re: stringzugriff - wie könnte ich das regeln
 
Zitat:

Zitat von meisteralex
hab jetzt 3 timer auf einer form laufen , die alle 10ms den gleichen string bearbeiten...?

Die werden sich dann wohl kaum gegenseitig auf die Füße treten. Stell Dir vor, drei Menschen laufen im Kreis (blöde Vorstellung, aber stell Dir vor, es sind Soldaten, dann klappts :mrgreen:). Wenn alle gleich schnell laufen, müssen sie sich nie abstimmen. Läuft aber der eine etwas schneller, oder der Andere etwas langsamer, kommt es zwangsweise zu 'Synchronisationsproblemen', bzw. auf gut Deutsch, Aufdenfußtretismus.

Sowas testet man mit threads, die nonstop auf die Strings zugreifen. Dann ist die Warscheinlichkeit größer, das sie sich mal stören. Aber glaub mir, mit CriticalSections bist Du auf der sicheren Seite. An etwas Anderem liegt es nicht.

meisteralex 29. Dez 2005 13:42

Re: stringzugriff - wie könnte ich das regeln
 
jut werd es einbauen und euch verklagen wenns nicht stimmt.
ne mal im ernst vielen dank für die bemühungen , denke auch dass es klappen wird

alzaimar 29. Dez 2005 14:37

Re: stringzugriff - wie könnte ich das regeln
 
Zitat:

Zitat von meisteralex
jut werd es einbauen und euch verklagen wenns nicht stimmt.

Endlich mal wat los hier in den Laden :mrgreen:

meisteralex 5. Jan 2006 13:52

Re: stringzugriff - wie könnte ich das regeln
 
hmm hat leider doch nicht funktioniert????

es ist, so das der Sring an manchmal an einer Stelle einfach abgeschnitten wird. sprich, auch hinterher nicht mehr angefügt wird

Statt des richtigen Resultates " |NFA|Ich bin ein neues Fenster|NFE| |MBA|x,y|MBE| "
bekomme ich also z.b " |NFA|Ich bin ein neu|MBA|x,y|MBE| "
oder " |NFA|Ich bin ein neues Fen|MBA|x,y|MBE| "

weiß irgendjemand noch ne Lösung ?

meisteralex 5. Jan 2006 14:43

Re: stringzugriff - wie könnte ich das regeln
 
hmm niemand ne idee ? das komische ist auch, das es erst so ab dem 35000 zeichen auftauch, dann aber vermehrt
wäre so ne art puffer für die string ne idee ?
weiß jemand wie man sowas programmiert
?

alzaimar 5. Jan 2006 15:05

Re: stringzugriff - wie könnte ich das regeln
 
Versteh ich nicht, das das *nicht* funktionieren soll. Kannst Du den Code nicht mal posten?

meisteralex 6. Jan 2006 09:13

Re: stringzugriff - wie könnte ich das regeln
 
Jut, also im weisentlichen geht es darum das ich zwei Timerroutinen hab, welche auf den gleichen String zugreifen

Delphi-Quellcode:

//capturestring:string ist als globale Variable definiert



procedure Thauptform.tmrMouselogTimer(Sender: TObject);
var
x,y:integer;
aktuellerfenstertitel:string;
begin
x:= getmousex();
y:= getmousey();
 
        aktuellerfenstertitel := lesefenstertitel();
        if (aktuellerfenstertitel <> alterfenstertitel) then //Fenstertitel geändert
          begin
         
           
            alterfenstertitel := aktuellerfenstertitel;

            MyCS.Enter;
            Try  //wenn fenster sich geändert hat, diese information mit der aktuellen mausposition in den string schreiben
              capturestring := capturestring + '|NWA|'+ aktuellerfenstertitel +'|NWE|'+'|MPA|'+inttostr(x)+','+inttostr(y)+'|MPE|';
            Finally
              MyCS.Leave;
            End;

          end
        else
          begin
            MyCS.Enter;
            Try  //wenn fenster sich nicht geänder hat, nur die aktuelle mouseposition in den string schreiben
              capturestring := capturestring + '|MPA|'+inttostr(x)+','+inttostr(y)+'|MPE|';
            Finally
              MyCS.Leave;
            End;
          end;
 
end;



procedure Thauptform.tmrschreibeTimestampTimer(Sender: TObject);
begin
//erst prüfen wir ob die Zeitinformation erneuert werden muss
//es wird geprüft ob eine stunde vergangen ist

if (lasttimestamp + 3600 < datetimetounix(now())) then
  begin
    info('schreibe timestamp');
    MyCS.Enter;
    Try
      capturestring := capturestring + '|DTA|' + inttostr(datetimetounix(now())) + '|DTE|';
    Finally
      MyCS.Leave;
    End;
    lasttimestamp := datetimetounix(now());
    oldcapturestring := capturestring;
  end;
end;
//die Prozedur schreibt also jede Stunde in die Variable capturestiring den aktuellen Unixtimestamp

Problem des ganzen ist, wie schohn beschrieben, dass, wenn stündlich ein Timestamp in den String geschrieben wird, dieser den aktuellen Datenfluss abhackt
sprich aus dem richtigem Ergebnis '|NWA|Explorer|NWE||MPA|333,444|MPE||DTA|328974893 729|DTE|' wird z.b. '|NWA|Explo|DTA|328974893729|DTE|' wobei der Teil der abgehackt wird ('rer|NWE||MPA|333,444|MPE|') kommplett überschrieben wird

marabu 6. Jan 2006 12:55

Re: stringzugriff - wie könnte ich das regeln
 
Ein paar grundsätzliche Anmerkungen:

Wenn du Ereignisse deiner eigenen Anwendung protokollieren willst, dann solltest du keine Timer verwenden, sondern die events direkt anzapfen. Wenn du systemweite Ereignisse protokollieren willst, dann wirst du dich besser über hooks einklinken, auch hier sind Timer kein gutes Mittel.

Wenn deine Timer mit einem 10ms Intervall arbeiten, dann solltest du Vorkehrungen treffen, dass sie sich nicht selbst überholen. Du kannst den Wiedereintritt verhindern, indem du den Timer beim Eintritt in die Timer-Routine deaktivierst und zum Schluß wieder aktivierst. Wenn das Timer-Intervall als Takt arbeitet, dann kannst du deinen Code beim Wiedereintritt auch einfach aussetzen lassen.

Wenn du deine Protokollierung in einem string zwischenspeicherst, dann wächst der Zeitaufwand für das Neuzuordnen von Speicher. Noch schlimmer bemerkbar machen sich durch die ständige Speicheranforderung und -Freigabe die gelegentlich notwendigen Kompaktläufe des heap managers. Ein Intervall von 10ms reicht dann nicht immer aus, um den Umspeichervorgang korrekt zu beenden.

Wenn du deine Protokolleinträge so wie gezeigt in einen string speicherst, dann kannst du sie auch gleich wegwerfen. Eine spätere Auswertung deiner Protokolldatei ist viel zu kompliziert. Besser du sammelst deine Einträge in einer StringList. Und versuche eine einheitliches Format zu entwickeln, was die Auswertung stark vereinfachen würde.

Freundliche Grüße vom marabu

alzaimar 6. Jan 2006 13:21

Re: stringzugriff - wie könnte ich das regeln
 
Liste der Anhänge anzeigen (Anzahl: 1)
Erstmal eins vorneweg: Nimm Dir das, was der marabu sagt, mal zu Herzen.

Dessenungeachtet habe ich ein Testprogramm geschrieben, das derzeit einfach nonstop läuft, ohne irgendwelche Fehler zu produzieren ... Ich habe aber die Speicherung des Strings in eine Klasse gepackt, das ist ein bisserl sauberer...

meisteralex 6. Jan 2006 14:11

Re: stringzugriff - wie könnte ich das regeln
 
wie kann ich denn die events direkt anzapfen ? bzw. wie funktioniert das mit den hooks ?

marabu 6. Jan 2006 19:36

Re: stringzugriff - wie könnte ich das regeln
 
Mit dem direkten Anzapfen meinte ich, dass du im passenden event handler deiner Form (OnShow) deinen Protokolleintrag erzeugst. Hooks brauchst du nur, wenn du systemweit überwachen möchtest. Wenn mich nicht alles täuscht, dann solltest du zu diesem Thema auch in der DP etwas finden. Ansonsten hat der Windows Platform SDK ein passendes Kapitel.

marabu


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:26 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