Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Synchronize inerhalb globaler Funktion durchführen (https://www.delphipraxis.net/158410-synchronize-inerhalb-globaler-funktion-durchfuehren.html)

schwa226 16. Feb 2011 16:06

Synchronize inerhalb globaler Funktion durchführen
 
Hallo,

ich habe ein gleines Synchronize Problem!

Ich habe einen Thread der mir Daten in eine TThreadList reingibt oder rausnimmt.
Der Thread ruft nun die LockList auf und befindet sich somit in der Critical Section.
Wie kann ich aber nun in dieser Funktion auch noch die VCL updaten?

Ein einfaches zugreifen auf das Memo in der VCL statt einem Synchronize führt zu Problemen da der Thread zwar gegen andere Threads sicher ist, aber nicht mit der VCL im Sync ist.

Delphi-Quellcode:
procedure RemoveData(Data : Pointer);
var
  List : TList;
  i : Integer;
begin

  List := fStringList.LockList;

  try
    for i := 0 to List.Count - 1 do
    begin
      if List[i] = Data then
      begin
        List.Delete(i);
        ---> Synchronize(RemoveStringInMemo);      ???????????????
      end;
    end;
  finally
    fStringList.Unlocklist;
  end;
end;

Memnarch 16. Feb 2011 16:11

AW: Synchronize inerhalb globaler Funktion durchführen
 
Also ich versteh das problem nicht ganz o.O.
Mal kurz zum mitschreiben:
Du veränderst den inhalt einer stringlist, und nach dem manipulieren soll der inhalt mit dem Memo synchronisiert werden?

Fals ich obiges richtig verstanden habe:

Schreib ne prozedur die das macht und rufe die per Synchronize aus dem thread auf o.O

MFG
Memnarch

Uwe Raabe 16. Feb 2011 16:13

AW: Synchronize inerhalb globaler Funktion durchführen
 
Man müsste jetzt noch sehen, wie RemoveStringInMemo herausfindet, welchen String es entfernen soll. Etwas mehr Code wäre hilfreich.

schwa226 16. Feb 2011 16:24

AW: Synchronize inerhalb globaler Funktion durchführen
 
Ich habe natürlich den Code oben nur kurz reingetippt ;)

Eigentlich ist die Funktion RemoveData in einer Class.
Wird die Funktion RemoveData von einem Thread aufgerufen wird aus der TThreadList das Item entfernt.

Danach wollte ich mit einer Funktion der Class ein Stringgrid in der Hauptform Updaten.
Beim AutoSizeGrid (anpassen der GridSpaltenbreite) was beim Updaten ausgeführt wird gibt es aber dann Probleme.

Ich habe jetzt auch versucht meiner Class den TThread zu übergeben, aber dann bekomme ich die Meldung das Synchronize protected ist.

Also kann Synchronize nur im Thread selber aufgerufen werden.
Ich hatte mir gedacht, ich kann eine Funktion machen, wo Daten der TThreadList bearbeitet werden und auch gleich das StringGrid in der VCL ein Update erhält.

Nun glaube ich, dass ich halt im Thread die TThreadList bearbeiten muss und dann noch extra im Thread danach das Synchronize durchführen muss.

Memnarch 16. Feb 2011 16:33

AW: Synchronize inerhalb globaler Funktion durchführen
 
natürlich get Synchronize nur innerhalb eines Threads. Dieser funktion musst du dan die Funktion übergeben, die du synchronisieren möchtest(also z.B. die updatefunktion).

MFG
Memnarch

schwa226 16. Feb 2011 16:47

AW: Synchronize inerhalb globaler Funktion durchführen
 
Habe es nun so gemacht!

Ich gebe in eine Private Var meine Daten und rufe dann das Synchronize im Thread auf.
Dies Sync Procedure ruft mit dann die Globale funktion auf und schraubt am StringGrid herum.
Dann gibt es keine Probleme.

Wie sieht es nun aus, wenn ein Thread das Synchronize ausführt und darin das LockList durchführt und nun ein anderer Thread auch das Synchronize ausführen will.
Wartet da der zweite thread darauf, dass der erste die Sync Procedure wieder verlassen hat oder kann es hier einen Deadlock führen?

Uwe Raabe 16. Feb 2011 18:19

AW: Synchronize inerhalb globaler Funktion durchführen
 
Ohne den konkreten Code, kann ich immer noch nur raten...

Aber: Wenn innerhalb RemoveStringInMemo ein LockList aufgerufen wird, darfst du während du das Synchronize aufrufst keien Lock auf die Liste haben, sonst ahst du schon deinen DeadLock. Durch das Synchronize ist dein Thread blockiert und im HauptThread geht das Lock nicht durch.

Wenn immer nur ein Element aus der Liste entfernt wird, merk dir doch den Index und ruf Synchronize nach dem Unlock auf.

Eventuell kannst du auch statt Synchronize Queue aufrufen, aber das kann dann ganz andere Nebeneffekte haben. Es gibt eben keine generelle Regel.

himitsu 16. Feb 2011 18:26

AW: Synchronize inerhalb globaler Funktion durchführen
 
TThread bietet Synchronize in mehreren Varianten, einige als Klassen-Methode, welche man direkt über
Delphi-Quellcode:
TThread.Synchronize(nil, MyProc);
nutzen kann.

Entweder mit einer Prozedur (Delphi-Referenz durchsuchenTThreadProcedure) und womöglich mit einer globalen Variable (neuerdings auch als anonyme Methode),
oder als Methode (Delphi-Referenz durchsuchenTThreadMethod) irgendeiner Klasse, mit einem Feld in dieser Klasse.

Sir Rufo 16. Feb 2011 18:49

AW: Synchronize inerhalb globaler Funktion durchführen
 
Zitat:

Zitat von schwa226 (Beitrag 1082265)
Wie sieht es nun aus, wenn ein Thread das Synchronize ausführt und darin das LockList durchführt und nun ein anderer Thread auch das Synchronize ausführen will.
Wartet da der zweite thread darauf, dass der erste die Sync Procedure wieder verlassen hat oder kann es hier einen Deadlock führen?

Deadlock gibt es nicht ... weil das Locken auch nichts bringt.

Eine CriticalSection darf unter der gleichen ThreadID sooft betreten werden wie man lustig ist.
Und wenn der Aufruf per Sync erfolgt, dann befindest du dich im Kontext von MainThreadID!

Somit bringt dir die CriticalSection da nix ausser verschwendete Bytes im Source und Code.

Wer es nicht glaubt ;) das geht und wird auch immer brav aufgerufen
Delphi-Quellcode:
procedure RemoveData(Data : Pointer);
var
  List : TList;
  i : Integer;
begin
  // Da aus dem Thread mit Sync aufgerufen wird
  // ist diese Bedingung immer erfüllt
  // und kann daher auch entsorgt werden
  if MainThreadID = GetCurrentThreadID then
  begin

      for i := 0 to List.Count - 1 do
      begin
        if List[i] = Data then
        begin

          List.Delete( i );
          // Hier noch der Aufruf zur Aktualisierung des Memos
        end;
      end;

  end;
end;
Es ist auch immer hilfreich an gewissen Stellen mit OutputDebugString oder dem Schreiben einer Log-Datei oder mit einem Haltepunkt im Debugger die Statuswerte zu prüfen.
(z.B. GetCurrentThreadID und MainThreadID ;) )

himitsu 16. Feb 2011 19:21

AW: Synchronize inerhalb globaler Funktion durchführen
 
Zitat:

Wie sieht es nun aus, wenn ein Thread das Synchronize ausführt und darin das LockList durchführt und nun ein anderer Thread auch das Synchronize ausführen will.
Abgesehn davon, daß eh nur eine der Synchronize-Prozeduren gleichzeitig ausgeführt wird.
Also wenn ein Thread ein LockList macht, dann sollte er das am Ende auch wieder freigeben und nachdem dieser Synchronizeaufruf fertig abgearbeitet wurde, erst dann wird das andere Synchornize ausgefphrt und die Liste wäre ja schonwieder frei.
Gut, und zusärtlich das schon erwähnte Verhalten der CS, welche praktisch nur für andere Threads sperrt ... Synchronize-Prozeduren laufen ja immer im Hauptthread (dem der VCL) ab.


Alle Zeitangaben in WEZ +1. Es ist jetzt 23:22 Uhr.
Seite 1 von 2  1 2      

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