AGB  ·  Datenschutz  ·  Impressum  







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

Änderungen von Variablen synchronisieren

Ein Thema von Breager · begonnen am 17. Mär 2012 · letzter Beitrag vom 20. Mär 2012
Antwort Antwort
Seite 1 von 4  1 23     Letzte »    
Breager

Registriert seit: 18. Feb 2012
40 Beiträge
 
#1

Änderungen von Variablen synchronisieren

  Alt 17. Mär 2012, 10:58
Hallo,

ich hoffe, der Titel ist treffend. Ich habe eine Variable vom Typ String, die sowohl innerhalb eines Threads als auch außerhalb des Threads verändert werden kann. Die Wahrscheinlichkeit ist wohl sehr gering, aber ich befürchte, dass es theoretisch zu Problemen kommen könnte, wenn ich versuche, den Wert dieser Variablen gleichzeitig innerhalb des Threads und außerhalb des Threads zu ändern.

Hier mein Lösungsversuch:
Delphi-Quellcode:
Var ThreadString:AnsiString;
    TreadString_Locked:Boolean;

//Innerhalb des Threads
Begin
...
 ThreadString_Locked:=True;
 ThreadString:='Neuer Wert';
 ThreadString_Locked:=False;
...
End;

//außerhalb des Threads:

Function SetThreadString(s:AnsiString):Boolean;
Var TimeOut:Integer;
Begin
 TimeOut:=0;
 Repeat
 IF not(ThreadString_Locked) then
    BEGIN
     ThreadString:=s;
     Result:=True;
    END ELSE
     Result:=False;

 Inc(TimeOut);
Until TimeOut>1000;
End;
Solange der Wert innerhalb des Threads durch die Variable ThreadString_Locked gesperrt ist, kann der Variablen außerhalb des Threads nichts zugewiesen werden.

Ist dieser Ansatz sinnvoll bzw., gibt es eine einfachere oder besser Lösung?

Gruß

Geändert von Breager (17. Mär 2012 um 11:02 Uhr)
  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: Änderungen von Variablen synchronisieren

  Alt 17. Mär 2012, 11:11
Jo, z.B. Delphi-Referenz durchsuchenTCriticalSection

und auch mal hier schauen Hier im Forum suchenTCriticalSection
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 Aphton
Aphton

Registriert seit: 31. Mai 2009
1.198 Beiträge
 
Turbo Delphi für Win32
 
#3

AW: Änderungen von Variablen synchronisieren

  Alt 17. Mär 2012, 12:16
Apropos Timeout -> du hast da nen Vergleich mit 1000 gemacht, was evt. impliziert, dass du wirklich 1000 ms (1 sek) warten möchtest. Das ist aber nicht der Fall.. Das sind einfach 1000 Schleifendurchläufe; daher ist das auch abhängig von der Prozessorgeschwindigkeit. Verarbeitet dein Prozessor einen Schleifendurchgang in genau einer ms, dann würde das stimmen, nur ist das nicht der Fall. Diese Schleife ist binnen kürzester Zeit durchlaufen (<10ms?)

...nur ne Kleinigkeit ^^
das Erkennen beginnt, wenn der Erkennende vom zu Erkennenden Abstand nimmt
MfG
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Änderungen von Variablen synchronisieren

  Alt 17. Mär 2012, 13:47
Booleans sind nicht threadsicher, vorallem da sie nichtmal atomar änderbar sind, da die CPU mir kompletten Registern arbeitet und dann nur die Bytes raus ANDed und SCHIFTet.
Die CPUs kennen da einen speziellen Befehl LOCK

z.B. LOCK MOV [EAX], EDX statt MOV [EAX], EDX .
Und die WinAPI kennt die Interlocked-Behle, wie MSDN-Library durchsuchenInterlockedExchange.


Deine "innere" Änderung von ThreadString ist nicht abgesichert, denn da wird nicht geprüft, ob der String gerade von SetThreadString verändert wird.

Gut, man könnte jetzt beide Zeiten absichern und dann äußere und inner Änderungen nur über dieses SetThreadString ausführen,
Delphi-Quellcode:
Function SetThreadString(s:AnsiString):Boolean;
Var TimeOut:Integer;
Begin
 TimeOut:=0;
 Repeat
   IF not(ThreadString_Locked) then
    BEGIN
     ThreadString_Locked:=True;
     ThreadString:=s;
     ThreadString_Locked:=False;
     Result:=True;
    END ELSE
     Result:=False;

 Inc(TimeOut);
Until TimeOut>1000;
End;
aber hier kann es immernoch vorkommen, daß mehrere Threads gleichzeitig durch das IF kommen und :=True setzen, da diese Beiden erst Recht nicht atomar sind.

Ich hatte letzens die CriticalSection über TryEnter und eine Schleife mit einem TimeOut versehn.
Schön ist das nicht unbedingt, aber es funktioniert wenigstens.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.
  Mit Zitat antworten Zitat
Breager

Registriert seit: 18. Feb 2012
40 Beiträge
 
#5

AW: Änderungen von Variablen synchronisieren

  Alt 17. Mär 2012, 18:50
Vielen Dank für Eure Antworten!

Mir brummt schon ganz schön der Schädel. Vielleicht warte ich doch lieber, bis der Thread beendet wurde

Brauche ich zum Lesen auch eine CriticalSection? Wird der Code innerhalb der CriticalSection in eine Warteschleife gelegt und später abgearbeitet oder einfach nicht ausgeführt/ignoriert? Letzteres wäre vorallem beim Lesen ungünstig.

Zitat von himitsu:
Ich hatte letzens die CriticalSection über TryEnter und eine Schleife mit einem TimeOut versehn.
Danke. Im Grunde also das, was ich mit meinem Code erreichen möchte (ein Pollen sozusagen).

Bin gerade über TMultiReadExclusiveWriteSynchronizer gestolpert, was haltet ihr davon? Ich muss den Wert vorwiegend lesen.
  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
 
#6

AW: Änderungen von Variablen synchronisieren

  Alt 17. Mär 2012, 21:01
Eigentlich ist das mit der TCriticalSection sehr einfach.

Stell dir eine Kreuzung vor. Die beiden Straßen sind einmal der MainThread und der Thread den du laufen lässt. Die CriticalSection ist nun die Ampel, die dafür sorgt, dass über den Kreuzungspunkt (Zugriff auf die Variable) immer nur eine Fahrbahn (Thread) freigegeben ist.

Delphi-Quellcode:
TMyThread = class( TThread )
strict private
  FCS : TCriticalSection;
private
  FIntStr : string;
  procedure SetIntStr( const Value : string );
  function GetIntStr : string;
protected
  procedure Execute; override;
public
  property IntStr : string read GetIntStr write SetIntStr;
end;

...

procedure SetIntStr( const Value : string );
begin
  FCS.Enter; // Betreten der CS
  try
    FIntStr := Value;
  finally
    FCS.Leave; // Verlassen der CS
  end;
end;

function GetIntStr : string;
begin
  FCS.Enter; // Betreten der CS
  try
    Result := FIntStr;
  finally
    FCS.Leave; // Verlassen der CS
  end;
end;
Bei FCS.Enter wird solange gewartet, bis die CriticalSection frei ist und dann betreten.
Innerhalb eines Thread-Kontexts darf die CS sooft betreten werden, wie man möchte. Die CS sperrt ja nur gegen Zugriffe durch unterschiedliche Thread-Kontexte.

Die Getter und Setter der Eigenschaft kümmern sich nun darum, dass der Zugriff geregelt wird, egal aus welchem Thread-Kontext man darauf zugreift.
Aber ... innerhalb des Threads könnte man ja direkt auf FIntStr zugreifen, aber dieser Zugriff ist nicht abgesicht (über die CS), also sollte der Zugriff auch innerhalb des Threads über die Eigenschaft und nicht über das Feld erfolgen.
Delphi-Quellcode:
procedure TMyThread.Execute;
begin
  while not Terminated do
  begin
    ...
    // FIntStr := 'So nicht';
    IntStr := 'So geht das';
    ...
  end;
end;
end;
Der Vollständigkeit halber sei noch erwähnt, dass die Instanz von FCS natürlich von TMyThread im Constructor erzeugt und im Destructor wieder freigegeben werden sollte bzw. muss.
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 2012 um 21:05 Uhr)
  Mit Zitat antworten Zitat
Breager

Registriert seit: 18. Feb 2012
40 Beiträge
 
#7

AW: Änderungen von Variablen synchronisieren

  Alt 17. Mär 2012, 21:53
Danke Sir Rufo

Habs gerade selbst getestet und gesehen, dass alles schön sauber nacheinander abgearbeitet wird.
Ich benutze in meinem Programm eine TList, dessen Items ich jeweils einen Record zuweise. Ein Bestandteil dieses Records ist die String-Variable (in meinem Beispiel ThreadStrg).

Jedes Bearbeiten der Liste (Add, Insert, Delete, Exchange, Clear) im Hauptthread und natürlich das Ändern sowie das Lesen des Strings im Thread und im Hauptthread muss ich also einfach in die CriticalSection packen.
Zitat von Sir Rufo:
Der Vollständigkeit halber sei noch erwähnt, dass die Instanz von FCS natürlich von TMyThread im Constructor erzeugt und im Destructor wieder freigegeben werden sollte bzw. muss.
Außerdem muss die Unit SyncObjs eingebunden werden.

Für meinen Fall ist es dann wahrscheinlich am sinnvollsten, die Instanz FCS zusammen mit TList zu erstellen und wieder freizugeben?

@Aphton: Danke für Deinen Hinweis. Das ist mir schon klar. Für ein zeitgebundenes Timeout würde ich etwas anders an die Sache rangehen.

Geändert von Breager (17. Mär 2012 um 22:08 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

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

AW: Änderungen von Variablen synchronisieren

  Alt 17. Mär 2012, 23:56
Microsoft hat leider die Verwaltung der CS umgestllt.
In den Debuginfos der CS gibt es eigentlich ein Event-Objekt, an welches ich mich dranhängen wollte, um nicht pollen zu müssen, aber leider ist dort, zumindestens in Win7/Server2008/Server2011 immer nur "Nichts" (0) eingetragen.

In der Unit SyncObjs gibt es auch Objekte, welche ein TimeOut verwenden können.



PS: Deine 1000-Schleifendurchläufe dürften schneller sein, als die Speicherverwaltung eines Strings, was sich etwas ungünstig auswirken dürfte.
Neuste Erkenntnis:
Seit Pos einen dritten Parameter hat,
wird PoSex im Delphi viel seltener praktiziert.

Geändert von himitsu (18. Mär 2012 um 00:01 Uhr)
  Mit Zitat antworten Zitat
Breager

Registriert seit: 18. Feb 2012
40 Beiträge
 
#9

AW: Änderungen von Variablen synchronisieren

  Alt 18. Mär 2012, 01:46
Danke himitsu!

Das klingt nicht so gut

Hier mal ein Versuch, das ganze mit InterlockedExchange sicher zu machen:
Delphi-Quellcode:
Var ThreadString:AnsiString;
    ThreadString_Locked:Integer;
...
ThreadString_Locked:=Integer(False);
...

Function SetThreadString(S:AnsiString):Boolean;
Var TimeOut:Integer;
Begin
 TimeOut:=0;
 Repeat
  IF InterlockedExchange(ThreadString_Locked,Integer(True)) = 0 then
     BEGIN
      ThreadString:=S;
      InterlockedExchange(ThreadString_Locked,Integer(False));
      Result:=True;
     END ELSE
      Result:=False;
  Inc(TimeOut);
 Until (TimeOut>1000) OR Result;
End;
Das weitere Verarbeiten der Liste (Sortieren, etc.) findet nur im Mainthread statt. Hierbei müsste ich einfach überprüfen, ob der Thread aktiv ist oder ThreadString_Locked auf True gesetzt ist.

Mal noch eine generelle Frage: Solange ich den Wert einer globalen Variablen nur innerhalb "eines" Threads ändere, kann doch eigentlich nicht passieren, und beim Lesen doch sowieso nichts?
  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
 
#10

AW: Änderungen von Variablen synchronisieren

  Alt 18. Mär 2012, 02:17
Mal noch eine generelle Frage: Solange ich den Wert einer globalen Variablen nur innerhalb "eines" Threads ändere, kann doch eigentlich nicht passieren, und beim Lesen doch sowieso nichts?
Wenn beide Threads nur lesend zugreifen, dann passiert IMHO nichts. Problematisch ist es wenn egal welcher Thread schreibend zugreift, dann geht von einem anderen Thread auch das Lesen in die Hose.

Ergo Lesen und Schreiben absichern.
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
Seite 1 von 4  1 23     Letzte »    


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 11:33 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