Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   GUI-Design mit VCL / FireMonkey / Common Controls (https://www.delphipraxis.net/18-gui-design-mit-vcl-firemonkey-common-controls/)
-   -   Delphi Liste Thread sicher abholen (https://www.delphipraxis.net/115283-liste-thread-sicher-abholen.html)

oki 9. Jun 2008 19:03


Liste Thread sicher abholen
 
Hi Leute!

ich bin mir bei meinem aktuellen Thema nicht ganz sicher wie ich es angehen soll. Folgende Voraussetzung:
Ich habe eine eigene Klasse mit dem Vorfahren TThread. Diese Klasse besitzt eine Public-Eigenschaft WindowList vom Typ TStringList. Der Thread aktualisiert diese Liste fortlaufend in seiner Execute-Methode.
Nun möchte ich mit meiner Anwendung den Inhalt der Liste abholen. Ich habe den Verdacht, dass das so einfach nicht geht wenn ich die Liste öffentlich mache und dann durch die Items iteriere um alles auszulesen. Mein Thread könnte da ja was in der Zwischenzeit ändern. Ein Ereignis mittels Synchronize will ich aber auch nicht aus dem Thread losschicken, da es nicht nötig ist die Anwendung zu informieren.

Hier mal der Code zur Klassendeklaration:

Delphi-Quellcode:
type
  TShutDownThread = class(TThread)
  private
    FWindowList : TWindowList;                               // Liste der aktiven Fenster
    FShutDownList : TShutDownList;                           // Schließliste
    function GetWinParamObj(index: Integer): TWinParamClass;
    function GetShutDownObj(index: Integer): TWinParamClass;
  protected
    procedure Execute; override;
    procedure UpdateWindowList;                              // Fensterliste aktualisieren
  public
    constructor Create(CreateSuspended: Boolean); reintroduce; virtual;

    property ShutDownList : TShutDownList read FShutDownList;
    property ShutDownObj [index : Integer] : TWinParamClass read GetShutDownObj;
    property WindowList : TWindowList read FWindowList;
    property WinParamObj [index : Integer] : TWinParamClass read GetWinParamObj;
  end;
Ich glaube, dass sollte Ärger geben:
Delphi-Quellcode:
  For Counter := 0 to ShutDownThread.WindowList.Count - 1 do begin
    Obj := ShutDownThread.WindowList.Objects[Counter];
    ... und dann lesen wir schön aus und zeigen an
  end;
Sorry, hab grad versehentlich den absenden Button gedrückt. Hier noch schnell der Rest.

Ich dächte, dass geht in die Hose. Die Frage ist nun, wie sollte ich die Items threadsicher aus dem Thread holen?

Gruß oki

[edit] nach Hinweis von sirius Fehler im Code gefixt! [/edit]

Apollonius 9. Jun 2008 19:09

Re: Liste Thread sicher abholen
 
Ja, das funktioniert nicht. Das beste ist, wenn du eine Critical Section einführst, die immer beim Bearbeiten der Liste betreten wird. Beim Auslesen solltest du die Section betreten, den Inhalt an eine neue Liste assignen und die Section verlassen und danach mit der neuen Liste weiterarbeiten, damit der Thread nicht zu lang aufgehalten wird.
Interessant könnten für dich auch einfach verkettete Listen sein, da man diese ganz ohne Critical Sections threadsicher bearbeiten kann - es werden nur die Interlocked-Funktionen benötigt.

oki 9. Jun 2008 19:17

Re: Liste Thread sicher abholen
 
Hi,

das war zu schnell.

Das mit dem Assign hatte ich mir auch schon überlegt. Etwa so:
Delphi-Quellcode:
procedure TShutDownThread.AssignWindowList(AList : TWindowList);
begin
  AList.Assign(FWindowList);
end;
Das geht sicher schneller, aber ist genau so'n Blödsinn. Was meinst du mit Critical Section? Beim Eintritt in die Procedure den Thread anhalten (Suspent) und nach Assign Resume?

Gruß

sirius 9. Jun 2008 19:24

Re: Liste Thread sicher abholen
 
Oben redest du von der FWindowList und in deinem Beispiel ist es Shutdownlist :gruebel:

Je nach Inhalt der Liste, wäre vielleicht eine TThreadList etwas für dich.

Apollonius 9. Jun 2008 19:24

Re: Liste Thread sicher abholen
 
Nein, ich meine eine Critical Section :wink: - das ist ein Objekt, dass von Windows zur Verfügung gestellt wird, in der Unit SyncObjs befindet sich eine Kapselung. Die Funktionsweise ist einfach: Wenn du eine Critical Section betreten willst, die schon ein anderer Thread besitzt, fällt der Thread in einen Wartezustand, der erst aufgehoben wird, wenn der Thread im Besitz der Critical Section sie genau so oft verlassen wir betreten hat (die Aufrufe können also durchaus gestapelt werden). Damit kannst du also kritische Abschnitte wie das Assign und das Bearbeiten der Liste schützen.

oki 9. Jun 2008 19:28

Re: Liste Thread sicher abholen
 
@sirius: Danke fur den Hinweis. Es soll natürlich die TWindowList sein. :oops: Blöder Fehler. Ich korrigiere das gleich.

@Apoll....: Da muss ich mal kurz die Hilfe bemühen. Scheint echt ne Bildungslücke bei mir zu sein. Melde mich wenn der Nebel weg ist.

Gruß oki

oki 9. Jun 2008 19:45

Re: Liste Thread sicher abholen
 
Hi sirius noch mal.

Ich stell mich im moment etwas schwerfällig an, aber was hilfts. Mir ist gerad nicht so richtig klar wie ich die ThreadList werwenden soll. Vieleicht denk ich auch zu kompliziert.

Einfach gedacht wurde ich es so machen.

Mein Thread ist ok, meine TWindowList ist ein Nachkomme von TThreadList und immer wenn ich die Einträge auslesen will mache ich folgendes:
Delphi-Quellcode:
procedure TShutDownThread.AssignWindowList(AList : TWindowList);
begin
  FWindowList.LockList;
  AList.Assign(FWindowList);
  FWindowList.UnlockList;
end;
@Apoll...:
Das mit dem Critical Section hört sich irgentwie gewaltig an. Macht sicher Eindruck und ist ein prodessioneller Weg, sieht aber im Moment so aus, als ob das umfangreicher wird als das was ich eigentlich nur machen will. Bis jetzt hab ich nur Einträge aus dm MSDN gefunden, und das sah nicht wie so eben mal schnell gemacht aus. Ich forsch da aber mal weiter. Dem Hinweis mit der Unit SyncObjs muß ich noch nachgehen.

gruß oki

sirius 9. Jun 2008 20:01

Re: Liste Thread sicher abholen
 
Ja, das ist soweit ok, wenn du auch das Einfügen mit TThreadList.add machst.
mit Locklist bekommst du übrigens auch direkt einen Zeiger auf die Liste darunter.

Kommt auch alles darauf an, was du für Sachen in der Liste hast. Denn ein Assign kopiert ja erstmal nur die Zeiger und nicht dessn Inhalt.

scp 9. Jun 2008 20:07

Re: Liste Thread sicher abholen
 
Critival Sections sind nicht kompliziert. Du brauchst nur eine Variable und vier Funktionen:

Delphi-Quellcode:
var
  mySection: RTL_CRITICAL_SECTION;
Einmalig rufst du folgendes auf:
Delphi-Quellcode:
InitializeCriticalSection(mySection);
Den Zugriff auf die Liste machst du in diesem Konstrukt:
Delphi-Quellcode:
EnterCriticalSection(mySection);
try
  //....
finally
  LeaveCriticalSection(mySection);
end;
Und zum Abschluss folgt dies:
Delphi-Quellcode:
DeleteCriticalSection(mySection);

oki 9. Jun 2008 20:08

Re: Liste Thread sicher abholen
 
Klar, ich hatte mir natürlich gedacht, dass ich im Execute ein LockList ausführe wenn ich die Liste bearbeite und ein UnlockList, wenn ich fertig bin. Das mit dem Assign-Beispiel war jetzt nur der Einfachheit halber.

Das blöde ist, dass meine WindowList eine StringList ist. Ich hatte mir aber schon gedacht die WindowList und die ShutDownList als ListItems in die ThreadList zu legen.

Gruß oki

oki 9. Jun 2008 20:11

Re: Liste Thread sicher abholen
 
Hi scp,

reicht es wenn ich Initialize und Delete im Create und Destroy aufrufe? Oder muss ich das jedesmal vor und nach Zugriff auf die Liste des Threads machen?

Gruß oki

Nachtrag: Auch wenn die Frage blöd erscheint, kommt das in meinen Thread oder in meine Hauptanwendung?

Apollonius 9. Jun 2008 20:11

Re: Liste Thread sicher abholen
 
Nein, die beiden rufst du nur einmal auf.
Wenn du dir mal die Implementation von TThreadList anschaust, wirst du auch feststellen, dass es nur eine TList mit einer Critical Section ist - es ist also nichts dabei, wenn du dir analog eine TThreadStringList schreibst. Zu schade, dass Delphi noch keine Generics kennt.

oki 9. Jun 2008 20:16

Re: Liste Thread sicher abholen
 
Danke für den Tipp. Ich schau mir das in TThreadList an und erweitere meine Listen oder meinen Thread (wenn ich durchsehe). So langsam kommt aber Licht ins dunkel. Ich lass den Thread erst mal offen und poste später mein Ergebnis.

Gruß oki

oki 9. Jun 2008 20:37

Re: Liste Thread sicher abholen
 
OK, ich hab mir das jetzt mal mit der ThreadList angesehen. Sah schlimmer aus als es ist. Ich hab noch nicht den kompletten Code, aber der Rahmen steht. Hier mein Ergebnis:

Delphi-Quellcode:
type
  TTShutDownThread = class(TThread)
  private
    FLock: TRTLCriticalSection;
    FShutDownList : TShutDownList;                           // Schließliste
    FWindowList : TWindowList;                               // Liste der aktiven Fenster
    function GetWinParamObj(index: Integer): TWinParamClass;
    function GetShutDownObj(index: Integer): TWinParamClass;
  protected
    procedure Execute; override;
    procedure Lock;
    procedure UnLock;
    procedure UpdateWindowList;                              // Fensterliste aktualisieren
  public
    constructor Create(CreateSuspended: Boolean); reintroduce; virtual;
    Destructor Destroy; override;

    Procedure GetWindowList(const AList : TWindowList);
  end;

implementation

{ TTShutDownThread }

constructor TTShutDownThread.Create(CreateSuspended: Boolean);
begin
  inherited;
  InitializeCriticalSection(FLock);
  FWindowList := TWindowList.Create;
  FShutDownList := TShutDownList.Create;
end;

destructor TTShutDownThread.Destroy;
begin
  Lock;
  try
    FreeAndNil(FWindowList);
    FreeAndNil(FShutDownList);
    inherited Destroy;
  finally
    Unlock;
    DeleteCriticalSection(FLock);
  end;
end;

procedure TTShutDownThread.Execute;
begin
  // hier die Behandlung der Listen mit vorherigen Lock und abschleißendem Unlock
end;

procedure TTShutDownThread.GetWindowList(const AList: TWindowList);
begin
  Lock;
  // Liste kopieren
  Unlock;
end;

procedure TTShutDownThread.Lock;
begin
  EnterCriticalSection(FLock);
end;

procedure TTShutDownThread.UnLock;
begin
  LeaveCriticalSection(FLock);
end;
Wenn ihr der Meinung seid das ist so ok, dann hab ich's begriffen und kann die Thread als beantwortet setzen. :lol:

Dank und Gruß oki

Apollonius 9. Jun 2008 20:43

Re: Liste Thread sicher abholen
 
Ein paar Kleinigkeiten fallen auf: Gib CreateSuspended im Konstruktor einfach weiter an Inherited, das macht es schon richtig, und spar dir damit auch die letzten beiden Zeilen, die so ziemlich falsch sind.
In GetWindowList sollte der Parameter const sein, da du ja nur ein Assign ausführst, aber keine neue Instanz zuweist.
Dein Destruktor sieht etwas seltsam aus, sollte aber funktionieren.

oki 9. Jun 2008 20:53

Re: Liste Thread sicher abholen
 
Hi,
das mit dem CreateSuspend habe ich mit Absicht so gemacht. Aber du hast wohl recht. Execute wird erst aufgerufen wenn der Constructor abgearbeitet wird. Da hab ich schief gedacht.

Das mit dem const nehme ich ohne Kommentar hin.

Bezüglich des Destructors habe ich mich an den Aufbau aus TThreadList gehalten. Ich hätte selber das inherited ans Ende gesetzt. So dachte ich mir, die haben sich vielleicht was dabei gedacht und es mir nur nicht mitgeteilt. Der Original Destructor der TThreadList sieht so aus:
Delphi-Quellcode:
destructor TThreadList.Destroy;
begin
  LockList;   // Make sure nobody else is inside the list.
  try
    FList.Free;
    inherited Destroy;
  finally
    UnlockList;
    DeleteCriticalSection(FLock);
  end;
end;
Ich werd jetzt mal den letzten Code editieren un deine Bemerkungen einarbeiten.

Gruß oki

Sir Rufo 9. Jun 2008 22:44

Re: Liste Thread sicher abholen
 
Hi,

warum machst du eigentlich nicht 2 Listen. 1x private und 1x public.
Und immer zwischendurch mit Synchronize eine Kopie von der private Liste auf die public Liste.
Das sollte doch von der Umsetzung/Handling schneller gehen.

Die CriticalSections sind durchaus interessant, aber wenn es mal schnell gehen muß, dann vielleicht doch die 5-Minuten-Ter.... :)

Oder bin ich da jetzt "heavy on the woodway" ?

Ich weiß das oki den synchronize nicht benutzen wollte, weil er die Anwendung nicht informieren möchte, aber tut er hier ja auch nicht :wink:

cu

Oliver

oki 10. Jun 2008 06:30

Re: Liste Thread sicher abholen
 
Moin Sir Rofu,

die Idee hört sich auch erst mal nicht schlecht an. Da ich mit dem Thema Threadsicheres arbeiten noch nicht so tief befreundet bin hab ich hier aber noch ne Menge Unsicherheiten.

Imho syncronisiert Synchonize ja die Ausführung einer Procedure über einen anderen Thread. Also am Beispiel eines Ereignisses sieht das bei mir immer so aus:
Delphi-Quellcode:

procedure TMyThread.Execute;
begin
  ....
  Synchronize(DoUpdate);
  ....
end;

procedure TMyThread.DoUpdate;
begin
  if Assignd(FOnUpdate) then
    FOnUpdate(self);                // hier mal ein eigenes NotifyEvent
end;
Mit dem Proceduraufruf DoUpdate wird also der Code des Threads, der eine Ereignisbehandlung für OnUpdate zur Verfügung stellt mit durchlaufen. Die Rückkehr erfolgt dann in die Execute-Methode des Thread.

Bei der von dir vorgesellten Variante würde der Zugriff auf die TempList (ich nenne jetzt mal die Übergabeliste so) nicht im Rahmen des Synchronize erfolgen. Es kommt mir so vor, dass mein MainThread dann eingentlich wieder nicht sicher zugreift. Eben nur auf die TempList. Das Problem scheint also nur verschoben zu sein.

Das sind jetzt aber nur meine Überlegungen zu dieser Variante. Kein Wissen!!!

Was mir zusätzlich nicht gefällt ist das führen eines Duplikates der Liste. Ich bin mir sicher, dass das nicht stört, aber mann hällt alle Daten ständig doppelt. Dabei bekomme ich immer einen blöden Geschmack im Mund. Wenn es vom Aufwand vertretbar ist, dann vermeide ich das lieber.

Im Moment halte ich die Idee mit CritcalSection sogar für sehr elegant. Ich implementiere das einmal in meinem Thread mit zugegeben minimalem Codeaufwand und kann eigentlich alle zukünftigen Zugriffe auf alle Eigneschaften meines Threads sicher implementieren.

Ich werd heute im laufe des Tages die Klasse weiter fertig stellen und von meinen Erfahrungen an dieser Stelle berichten.

Danke für deinen Beitrag, vielleicht kann noch jemand anderes etwas Licht in das Thema bringen,

liebe Grüße oki

oki 10. Jun 2008 09:50

Re: Liste Thread sicher abholen
 
Oh Backe, da läuft mächtig was schief. So geht es nicht. Folgendes Problem:
Mein Thread läuft sauber und ordentlich und arbeitet seine Execute-Methode ab.
Delphi-Quellcode:
procedure TShutDownThread.Execute;
begin
  while not Terminated do begin
    Lock;
    try
      FWindowList.EnumTopLevelWindows; // interne liste aktualisieren
      Sleep(Interval);                 // warte mal die eingestellte Zeit, nicht so 'ne Hektik (prefered 200)
    finally
      Unlock;
    end;
  end;
end;
Ok, sieht ja mal simpel und somit gut aus.

Jetzt meine Public-Methode des Threads zum Abholen der Werte der Liste.
Delphi-Quellcode:
procedure TShutDownThread.GetWindowList(const AList: TWindowList);
var
  WinParamObj: TWinParamClass;
begin
  if not Assigned(AList) then
    Exit;
  Lock;
  try
    AList.AssignList(FWindowList);
  finally
    UnLock;
  end;
end;
AssignList habe ich an dieser Stelle zusätzlich implementiert. Ist auch logisch und kein Hit. Sollte jemand damit Sorgen haben poste ich den Code.

Nun passiert folgendes. Rufe ich in meinem Programm diese Methode auf
Delphi-Quellcode:
procedure TForm1.RefreshWindowList;
var
  WindowList: TWindowList;
begin
  if assigned(FShutDownThread) then
  begin
    WindowList := TWindowList.Create;
    try
      FShutDownThread.GetWindowList(WindowList);
      ........
steht die Anwendung.
Ich habe mit dem Debugger die entsprechende Stelle gefunden. Es ist der Aufruf Lock in der Thread-Methode GetWindowList. Lock implementiert hier
Delphi-Quellcode:
procedure TShutDownThread.Lock;
begin
  EnterCriticalSection(FLock);
end;
Genau aus EnterCriticalSection kehrt die Procedur nicht zurück.

Da läuft doch was schief in meiner Logik. ich denke mal ich habe das was entscheidendes in der Handhabung der CriticalSection nicht verstanden oder bringe was in der Abarbeitung des Threads furcheinander. Das ist doch nur ein Verständnis und Handlingproblem meinerseits?

Wenn mir da mal einer auf die Sprünge helfen kann, währe toll.

Gruß oki

sirius 10. Jun 2008 10:00

Re: Liste Thread sicher abholen
 
Nimm mal das sleep in der Execute Methode aus dem try-Finally-Block bzw. aus dem Lock-Unlock-Block heraus.

oki 10. Jun 2008 10:03

Re: Liste Thread sicher abholen
 
gleicher Effekt!

oki

oki 10. Jun 2008 10:09

Re: Liste Thread sicher abholen
 
so klappts
Delphi-Quellcode:
procedure TShutDownThread.GetWindowList(const AList: TWindowList);
var
  WinParamObj: TWinParamClass;
begin
  if not Assigned(AList) then
    Exit;
//  Lock;
  try
    AList.AssignList(FWindowList);
  finally
//    UnLock;
  end;
end;
Nach meinem vorherigen Verständnis ist das dann aber wohl eben nicht mehr Thread-sicher. Das ich keine Fehlermeldung bekomme, darauf geb ich nichts. Könnte auch nur Glück sein.

oki

sirius 10. Jun 2008 10:11

Re: Liste Thread sicher abholen
 
Dann schau dir mal FLock.LockCount an und vergleiche vielleicht noch FLock.OwningThread.


Als Alternative gibts ja noch tryEnterCriticalSection. Aber das löst das eigentliche Problem nicht.


[roter KAsten]
Sieht nach Glück aus.

oki 10. Jun 2008 10:13

Re: Liste Thread sicher abholen
 
Tja, ich hab das Abholen der Liste in meinem Demo mal auf einen Timer gelegt, der alle 500ms ein ListView aktualisiert. Benimmt sich anständig. Ich trau dem aber immer noch nicht über den Weg. Viel schlimmer ist, dass mein Verständnis über CriticalSection über den Haufen ist wenn das so ok ist.

oki

roter Kasten :lol: ich lese mich mal durch LockCount und und OwningThread durch. So lass ich das auf keinen Fall stehen.

sirius 10. Jun 2008 10:32

Re: Liste Thread sicher abholen
 
Prinzipiell kann ich keinen fehler entdecken. Aber vielleicht geht irgendein Thread aus der Critical Section nicht mehr heraus. Das dürftest du an den Feldern von FLock sehen können (aber nicht selbst verändern!).

oki 10. Jun 2008 10:35

Re: Liste Thread sicher abholen
 
Liste der Anhänge anzeigen (Anzahl: 1)
Tja, tut mir leid, aber da komme ich nicht weiter. Die Hilfe spuckt nichts aus und die Deklaration in Windows bringt mich nicht sehr weit.
Delphi-Quellcode:
  _RTL_CRITICAL_SECTION = record
    DebugInfo: PRTLCriticalSectionDebug;
    LockCount: Longint;
    RecursionCount: Longint;
    OwningThread: THandle;
    LockSemaphore: THandle;
    Reserved: DWORD;
  end;
  {$EXTERNALSYM _RTL_CRITICAL_SECTION}
  TRTLCriticalSection = _RTL_CRITICAL_SECTION;
  RTL_CRITICAL_SECTION = _RTL_CRITICAL_SECTION;
  {$EXTERNALSYM RTL_CRITICAL_SECTION}
ich hab mich mal durch meine Getter-Methode sowie durch mein Execute debuggt. Der LockCount liegt konstant bei 0.

Im Anhang mal der Shot meines überwachten Ausdrucks FLock. Witzigerweise kommt mir da ein Versacht. Der ist wie folgt:

Kann es sein, dass der Aufruf nur für Zugriffe außerhalb der Klasse gültig ist. :gruebel: Nee, ich glaub das ist Quatsch.

oki

oki 10. Jun 2008 10:40

Re: Liste Thread sicher abholen
 
Jo man, roter Kasten ist heut mein Ding.

Weitere Zugriffe sollte es eigentlich nicht geben. Ich habe meinen Thread als Klasse in einer Unit (logisch). Meine Testanwendung besteht aus dem Formular, ListBox, Timer. Der Timer holt periodisch eine aktualisierte Liste und überträgt die Werte in das ListView. Da ist nicht viel dran, ist ja auch nur zum testen der Klasse.

Mein Thread macht nicht anderes als in Execute meine WindowList anzuweisen sich zu aktualisieren. Das macht sie mit EnumWindows. Sollte auch nicht der Hit sein.

Gruß oki

sirius 10. Jun 2008 10:44

Re: Liste Thread sicher abholen
 
Da mit die CS frei ist muss Lockcount -1 sein und OwningThread 0.
Jetzt schau noch mal den Record an bevor er im MainThread in das blockierende Lock geht. Und vergleiche owningthread mit MainThreadID (globale Variable in Unit System) und mit TThread.ThreadID.

oki 10. Jun 2008 10:58

Re: Liste Thread sicher abholen
 
Hi Sirius,

klar mach ich. Vorher noch 'ne Theorie. Ich war grad an der frischen Luft und hab nachgedacht. Folgendes.

Lock sorgt doch dafür, dass die zugreifenden Threads angehalten werden, damit es nicht zu kollisionen kommt (landläufig ausgedrückt). Somit sperre ich doch meinen Thread selbst, wenn ich Lock im Execute aufgerufen habe. In meiner GetterMethode sehe ich , dass LockCount = 0 ist. Das kann doch dann nur mein eigener Thread sein der in Execute Lock aufgerufen hat. Wenn ich jetzt über die Gettermethode des gleichen Threads Lock aufrufe sperre ich mich doch sozusagen selbst. Meine Idee ist jetzt folgende. Wenn ich in meinem Execute nur FLock.LockCount auf -1 prüfe und die Liste nur dann aktualisiere wenn dieser Wert tatsächlich -1 ist, dann hab ich doch die Kontrolle. Die Frage ist dann doch nur, ob ich Lock in der GetterMethode des Threads aufrufen darf oder das meinem MainThread (Anwendung) überlassen muß.

Ich teste das erst mal. Sorry.


teste teste teste ...

Ist doch Blödsin, wenn ich auf -1 getestet habe greif ich doch wieder nicht Threadsicher auf die Liste zu. Ein Lock von aussen nutzt dann auch nichts. Ich muss mich wohl erst mal von meinem Ansatz lösen. Da läuft doch was in meinem Gehirn krumm. Das einzige, was ich sicher glaube ist, dass ich mich selber sperre. Das scheint sicher.

Gruß oki

oki 10. Jun 2008 11:07

Re: Liste Thread sicher abholen
 
Mal ganz blöd gefragt, brauch einen Thread im Thread? oder bin ich grundsätzlich auf dem Holzweg. Ich debug jetzt erst mal um Sirius ein paar Antworten zu geben. Ist im Moment leichter als denken.

Gruß

alzaimar 10. Jun 2008 11:16

Re: Liste Thread sicher abholen
 
Ich verstehe einfach nicht, wieso Du keine TThreadlist nimmst... (Ich verstehe auch nicht, wieso Du nicht einfach eine 'TCriticalSection' verwendest. Dafür hast Du doch Delphi, damit Du dich nicht/seltener mit der API rumschlagen musst)
So gehts im Prinzip:
Delphi-Quellcode:
Var
  LocalList : TList;

Begin
  LocalList := MyThreadList.LockList;
  Try
//    ... tuwat mit der LocalList
  Finally
     MyThreadList.Unlock;
  End
End;
Dein Thread erstellt also eine neue EnumWindowsList und schmeisst Die dann per o.g. Code in die ThreadListe. Wenn jemand von außen die Liste will, macht er das genauso:

Delphi-Quellcode:
Procedure TMyThread.AssignToThreadList (aList : TList);
Var
  LocalList : TList;

Begin
  LocalList := MyThreadList.LockList;
  Try
     LocalList.Assign (aList);
  Finally
     MyThreadList.Unlock;
  End
End;

Procedure TMyThread.GetFromThreadList (aList : TList);
Var
  LocalList : TList;

Begin
  LocalList := MyThreadList.LockList;
  Try
     LocalList.AssignTo (aList);
  Finally
     MyThreadList.Unlock;
  End
End;


Procedure TMyThread.Excute;
Var
  MyList : TList;

Begin
  While not Terminated Do Begin
    CreateWindowList (MyList);
    AssignToThreaDList (MyList);
    Sleep(SomeTime); // sonst geht doch die CPU auf 100%
  End
Fertig.

Wenn Du eine CS willst, dann geht das damit (fast) genauso. Aber wieso das Rad neu entwickeln. Dazu gibt es schließlich die TThreadlist.

oki 10. Jun 2008 11:17

Re: Liste Thread sicher abholen
 
ok, debuggen kann ich also noch. Folgende und eingentlich auch logische Situation.

aktiviere ich Lock im Execute, so geht der LockCounter auf 0 und OwnerThread ist mein Thread. Aktiviere ich Lock in der GetterMethode des Thread durch Auffruf derselben durch meine Application, so ist OwnerThread meine Exe.

Damit scheint meine Theorie zu stimmen, dass ich mich selber (Thread) sperre wenn ich mit dem MainThread über die GetterMethode komme.

Es entsteht wieder Wissen :drunken: in meinem Kopf.

Nächster Schritt, wie mache ich jetzt die aktualisierung meiner Liste im Execute sicher?

Es geht vorwärts.

oki

oki 10. Jun 2008 11:28

Re: Liste Thread sicher abholen
 
[war ja klar, roter Kasten]

Hi alzaimar.

Du hast völlig recht! Zwei Gründe von meiner Seite.
1. Wollte ich das mit CriticalSection verstehen, was ich so langsam tue (auch wenn es der steinige Weg über ein erstmal falsches Vertehen ging).
2. In meinem Kopf ging irgent was verquerr, so das mir jetzt erst dämmert wie der richtige Weg ist. Da der Thread noch ne Menge mehr machen soll dachte ich, dass ich hier das Problem an einer Stelle zentral erschlagen könnte.

Ich mach jetzt erst mal 'ne kurze Pause an der Stelle und verpass meinem Kopf ne mentale Reinigung um die verqueren Gedanken los zu werden. Danach bau ich alles mal sauber um und wenn das ordentlich aussieht, dann poste ich meinen Weg.

Ich denk mal, das sollte auch für andere interessant sein.

Großen Dank an Sirius und natürlich auch an alzaimar für die Hilfe. Ich lass den Thread noch so lange offen, bis ich das saubere Ergebnis habe.

Gruß oki


[Edit] Nachtrag: Tut mir leid, wenn ich etwas verbohrt bin, aber ich schau erst mal bei TCriticalSection nach. Das hab ich ganz übersehen, sieht aber irgentwie nach meiner Ideallösung aus. Ich mach mal ein paar Lernstunden. Ist immer gut (und ich dachte ich kenn mich halbwegs mit Threads aus. Totaler Blödsinn).[/Edit]

alzaimar 10. Jun 2008 11:58

Re: Liste Thread sicher abholen
 
Hauptsache, man lernt was. CS sind allgemeiner und damit löst man das 'Threadlisten-Problem' auch.

Wichtig!!!! CS sperren nur unterschiedliche Threads, jedoch nicht konkurrente Aufrufe aus ein und demselben Thread. Wenn Du das willst, dann benötigst Du die große Schwester, die Semaphore.

oki 10. Jun 2008 12:08

Re: Liste Thread sicher abholen
 
Zitat:

Zitat von alzaimar
Wichtig!!!! CS sperren nur unterschiedliche Threads, jedoch nicht konkurrente Aufrufe aus ein und demselben Thread.

Genau so hab ich das verstanden. Ich will die Aktualisierung der Listen in meinem Thread sicher ausführen können. Die Abarbeitung innerhalb meines Threads konkuriert nicht. Das kann ich strukturiert in meinem Execute abarbeiten.

Vom Prinzip her will ich folgendes. Aktualisiere ich meine Listen sollen die Threads von außen warten bis ich fertig bin. Ist das so, dürfen die ran. Dann muss ich im Thread sicher stellen, dass ich erst anfange erneut zu aktualisieren wenn die von außen fertig sind. Ob den zweiten Teil TCriticalSection liefert ist mir noch nicht klar, den ersten aber sicher. Die OH sagt dazu zumindestens:
Zitat:

TCriticalSection ermöglicht es einem Thread in einer Multithread-Anwendung, andere Threads vorübergehend an dem Zugriff auf einen bestimmten Codebolck zu hindern.
Schaun wir mal.

oki

alzaimar 10. Jun 2008 12:13

Re: Liste Thread sicher abholen
 
Doch doch, die CS ist dein Freund. Einfach blind alle Zugriffe auf dein schützenswertes Objekt kapseln und gut is.

oki 10. Jun 2008 12:22

Re: Liste Thread sicher abholen
 
Ok dann auch noch mal von mir konkret nachgehagt (deine Nettigkeit muß ich ausnutzen :stupid: ).

Mein zu schützendes Object ist meine Liste, TCriticalSection bringe ich in meinem Thread als Member unter und den Schutzmechanismus schalte ich immer ein, wenn auf die Liste zugegriffen wird. Also sowohl in den Getter- und Settermethoden des Threads für den Zugriff auf die Listen von außen wie auch in meinem Execute wenn ich die Listen im Thread aktualisiere. Schlicht immer.
[Edit] Oder gehört die TCriticalSection in die Liste als Member? [/Edit]

Mein Thread ist sozusagen das Portal nach außen für meine Listen, macht und tut mit den Listen rum und kümmert sich nebenbei um die sauberen Zugriffe von Außen auf die Listen (also threadsicher). So würde ich es populärwissenschaftlich ausdrücken. :lol:

oki

[Edit] Schnell noch einen Rechtschreibfehler nach Hause geholt. [/Edit]

alzaimar 10. Jun 2008 12:50

Re: Liste Thread sicher abholen
 
Genauso würde ich das machen. CS ist ein privates Feld des Threads und schützt die öffentlichen Eigenschaften des Threads, sodaß sich Thread und Verwender (ein anderer Thread) nicht auf die Füße treten.

Allerdings ist es etwas hübscher, wenn die Liste selbst dafür sorgt, das man gar nicht ungeschützt an sie rankommt (=TThreadlist).

Du kannst spaßenshalber (wenn Du die CS gefressen hast) mal so eine threadsichere Stringliste bauen, die gibt es imho in der VCL nicht. Es ist zwar viel blöde Schreibarbeit (immer das Gleiche: CS.Enter try tu was finally CS.Leave) aber dann kannst Du das -rein schon wegen Pavlow- im Schlaf. :stupid:

Ach, immer ausnutzen. Bin ja selbst Schuld, wenn ich hilfsbereit bin :zwinker:

oki 10. Jun 2008 13:28

Re: Liste Thread sicher abholen
 
Ahhhmmm, so'n gepflegtes Mittagessen ist doch was wert.

Ich werd mal jetzt anfangen und den Code umsetzen. Das mit dem Tippen an der Tringliste [Edit] Ups, hatte doch was mit Unterwäsche zu tun und sollte StringList lauten :lol: [/Edit][Edit2]An der StringList tippen ist in diesem Kontext auch niedlich :lol: (ist mir grad so aufgefallen, Sorry)[/Edit2] seh ich nicht so kritisch. Da schreibt man sich dann mal eine neue Basisklasse TThreadStringList oder legt sich ein kleines Template an wenn man spezielle Klassen in Objects speichern will um sich das ständige Casten zu spaaren. Hab ich so auch mit einer ObjectList gemacht. Ist total easy.

Gruß oki

oki 10. Jun 2008 13:54

Re: Liste Thread sicher abholen
 
Menne, Erfolg auf der ganzen Linie :bounce2: !!!

Wenns denn auch wirklich sicher läuft? Aber das sollte es schon tun. Auf irgend was muss man sich halt auch einfach mal verlassen.

Der Basiscode ist auch erschreckend simpel. So hatte ich mir das auch vorgestellt.

Delphi-Quellcode:
type
  TShutDownThread = class(TThread)
  private
    FCS: TCriticalSection;                                   // CriticalSection
    FShutDownList : TShutDownList;                           // Schließliste
    FWindowList : TWindowList;                               // Liste der aktiven Fenster
    FInterval : Integer;                                     // Refreshzeit in ms
  protected
    procedure Execute; override;
    procedure UpdateWindowList;                              // Fensterliste aktualisieren
  public
    constructor Create(CreateSuspended: Boolean); reintroduce; virtual;
    Destructor Destroy; override;

    Procedure GetWindowList(const AList : TWindowList);      // Fensterliste abholen

    property Interval : Integer read FInterval write FInterval;
  end;

implementation

{ TTShutDownThread }

constructor TShutDownThread.Create(CreateSuspended: Boolean);
begin
  inherited;
  FCS := TCriticalSection.Create;
  FWindowList := TWindowList.Create;

  FShutDownList := TShutDownList.Create;

  FInterval := 200;
end;

destructor TShutDownThread.Destroy;
begin
  FCS.Enter;
  try
    FreeAndNil(FWindowList);
    FreeAndNil(FShutDownList);
    inherited Destroy;
  finally
    FCS.Leave;
    try FreeAndNil(FCS); except end;
  end;
end;

procedure TShutDownThread.Execute;
begin
  while not Terminated do begin
    FCS.Enter;
    try
      FWindowList.EnumTopLevelWindows;
      Sleep(Interval);
    finally
      FCS.Leave;
    end;
  end;
end;

procedure TShutDownThread.GetWindowList(const AList: TWindowList);
var
  WinParamObj: TWinParamClass;
begin
  if not Assigned(AList) then
    Exit;
  FCS.Enter;
  try
    AList.AssignList(FWindowList);
  finally
    FCS.Leave;
  end;
end;

procedure TShutDownThread.UpdateWindowList;
begin
  FWindowList.EnumTopLevelWindows;   // Alle Windows auflisten
end;
Ist eingendlich nicht viel für sooon langen Thread.

Ich hoffe jetzt kommt nicht einer um die Ecke und erklärt mir, dass das alles totaler Stuß ist was ich hier schreibe. Drücken wir mal die Daumen. Erläuterungen brauch jetzt wohl nicht mehr machen. Der Thread erzählt genug.

Herzlichen Dank an alle. Das sauber zu lösen war mir wichtig.

Gruß oki


Alle Zeitangaben in WEZ +1. Es ist jetzt 04:44 Uhr.
Seite 1 von 2  1 2      

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