Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Frage zu Thread und Ciritical Section (https://www.delphipraxis.net/68032-frage-zu-thread-und-ciritical-section.html)

McMorton 23. Apr 2006 20:00


Frage zu Thread und Ciritical Section
 
Hallo.

Ich habe eine Frage zum Thema Threads.

Ich habe einen Thread, der über eine Critical Section auf ein Element zugreift.
Ein anderes Objekt will ab und zu ebenfalls auf dieses Element zugreifen (ebennfalls über Critical Section).

Nun habe ich beim ersten Test festgestellt, das das Objekt nie Zeit bekommt zuzugreifen. Der Thread läuft ständig, und belegt die ganze Zeit die Critical Section.
Wenn ich eine kurze Pause im Thread einfüge, dann geht es. Aber nun läuft das Programm irgentwie "unrund". Wenn ich die Form mit der Maus verschieben will, bewegt es sich sehr hagelig.
Liegt das an dem Sleep Befehl?
Wie kann ich das Problem sonst lösen?

Hier der Code:

Delphi-Quellcode:
//Der Thread
procedure einThread.execute;
begin
  while not Terminated do
    begin
      try
        //Pause, ansonsten würde eine andere Critical Section keine Zeit bekommen
        sleep(20);
        FCritSect.Enter;
          //Zugriff auf ein Objekt (Lesefunktion von Indy10)
        FCritSect.Leave;    
      except      
      end;
    end;
end;


//Das andere Objekt
procedure Datensenden;
begin
  try
    self.FCritSect.Enter;
      //Zugriff auf ein Objekt (Schreifunktion von Indy10)
    self.FCritSect.Leave;
  except
  end;
end;

guste 23. Apr 2006 20:39

Re: Frage zu Thread und Ciritical Section
 
spontan fällt mir dazu finally statt except ein:

Delphi-Quellcode:
//Der Thread
procedure einThread.execute;
begin
  while not Terminated do
    begin
      try
        //Pause, ansonsten würde eine andere Critical Section keine Zeit bekommen
        sleep(20);
        FCritSect.Enter;
          //Zugriff auf ein Objekt (Lesefunktion von Indy10)
      finally
        FCritSect.Leave;    
      end;
    end;
end;


//Das andere Objekt
procedure Datensenden;
begin
  try
    self.FCritSect.Enter;
      //Zugriff auf ein Objekt (Schreifunktion von Indy10)
  finally
    self.FCritSect.Leave;
  end;
end;

tigerman33 24. Apr 2006 08:14

Re: Frage zu Thread und Ciritical Section
 
Wenn das andere Objekt Zugriff auf den Thread hat, könnte es diesen per Suspend schlafen legen und dann auf das Objekt zugreifen.
Eleganter fände ich allerdings, wenn dein Objekt quasi "anmeldet", dass es gerne schreiben möchte und daraufhin der Thread dementsprechend Rücksicht nimmt. Würde im Endeffekt so ziemlich auf das gleiche hinauslaufen wie ein Suspend, nur etwas anders verpackt.

himitsu 24. Apr 2006 08:47

Re: Frage zu Thread und Ciritical Section
 
Wenn der andere Thread nur manchmal (selten) auf das Objekt zugreift, dann könntest du ihm ja sowas wie MasterRecht geben, damit er vorrangig auf das Objekt zugreifen kann.
Hab aber keine Ahnung, ob sowas mit CiriticalSections möglich ist, da ich meine eigenen (nicht so überladenen) Methoden verwende Objekte/Speicherbereiche Threadsave zu machen ._.

mbamler 24. Apr 2006 09:07

Re: Frage zu Thread und Ciritical Section
 
Zitat:

Zitat von himitsu
Wenn der andere Thread nur manchmal (selten) auf das Objekt zugreift, dann könntest du ihm ja sowas wie MasterRecht geben, damit er vorrangig auf das Objekt zugreifen kann.
Hab aber keine Ahnung, ob sowas mit CiriticalSections möglich ist, da ich meine eigenen (nicht so überladenen) Methoden verwende Objekte/Speicherbereiche Threadsave zu machen ._.


Benutz doch Synchronize()
Das ist extra geschaffen, um in kritischen Abschnitten Threads die Kommunikation mit
andren Threads (so auch den Mainthread) zu ermöglichen...

Gruß
Matthias

McMorton 24. Apr 2006 22:35

Re: Frage zu Thread und Ciritical Section
 
Erstmal Danke für die Antworten.

Mir ist aufgefallen: sobald ich den Sleep-Befehl entferne, steigt die CPU-Auslastung auf 100%.

Aber hagelig bewegt sich die Form immer noch. Sobald ich den Thread stoppe läßt sie sich flüssig verschieben.

HolgerX 25. Apr 2006 04:57

Re: Frage zu Thread und Ciritical Section
 
Hallo,
hmm...
Zitat:

Zitat von McMorton
Mir ist aufgefallen: sobald ich den Sleep-Befehl entferne, steigt die CPU-Auslastung auf 100%.

Aber hagelig bewegt sich die Form immer noch. Sobald ich den Thread stoppe läßt sie sich flüssig verschieben.

Welche Priorotät hast Du deinem Thread gegeben ?
Gib im mal eine geringere und bedenke, das dieser Thread eigendlich immer im Prozess des MainThread läuft.
Solltest Du nur ein 'gelegendliches Prüfen benötigen, dann währe hier wohl eine einfache TTimer - Verwendung sinnvoller.

Ach ja das 'hagelige' Bewegen kommt einfach durch die Verarbeitung des Zugriffes innerhalb der critical Section, da der MainThread dafür unterbrochen wird (ähnlich wie Synchronize)!

Schuiii...

Holger

alzaimar 25. Apr 2006 07:25

Re: Frage zu Thread und Ciritical Section
 
Dein Ansatz ist falsch, die Idee mit dem Suspend im Prinzip richtig, aber leider auch im Detail falsch.
Erstmal ist aber korrekt, das der eine Thread nun nicht non-stop per Critical-Section auf den geschützten Bereich zugreifen muss, denke ich. Normalerweise sehen Threads doch so aus
Delphi-Quellcode:
Procedure TMyThread.Execute;
Begin
  While Not Terminated Do Begin
    WaitForSomethingToDoOrTerminated;
    If SomethingToDo Then DoIt;
 End;
End;
Willst Du z.B. ein Spiel programmieren, würde ein Timer dem Thread periodisch sagen können 'Do something': Der Thread erledigt diesen Job und wartet dann wieder auf den Nächsten. tigerman33 hat schon die Idee mit dem suspend gehabt, aber das ist unsauber, da man ja nicht weiss, was der Thread gerade macht. Besser ist es, über ein Synchronisationsobjekt mit dem Thread zu kommunizieren. Da wäre eine Semaphore oder ein Event gerade das Richtige. Die Funktion, die darauf wartet, das Synchronisationsobjekt (SO) ein Signal bekommt, heißt 'WaitForSingleObject' und... tut genau das: Es wartet, bis jemand das SO antriggert, und das sehr effizient (also mit 0% CPU-Last).

Ich arbeite mit Semaphoren. Eine Sempahore ist soetwas wie ein Zähler, der absolut threadsicher verwaltet wird. Wenn der Zähler 0 ist, dann wartet 'WaitForSingleObject' (WFSO). Sobald der Zähler>0, wird WFSO beendet und der Zähler um eins dekrementiert. WFSO wartet also, BIS der Zähler > 0 ist. Ist die Semaphore bereits > 0 beim Aufruf, wird die Semaphore sofort dekrementiert und WFSO beendet.

Die Semaphore wird mit 'ReleaseSemaphore' gesteuert.

Also:
1. CreateSemaphore im Create des Threads, CloseHandle im Destruktor.
2. WaitForSingleObject im Execute des Threads (lies genau die Möglichkeiten des Timeouts in der OH)
3. ReleaseSemaphore signalisiert, das der Thread einen Job zu erledigen hat.

McMorton 25. Apr 2006 23:11

Re: Frage zu Thread und Ciritical Section
 
Das mit der Semaphore versteh ich leider nicht.
So wie ich es zu verstehen gleube soll meine Hauptanwendung dann über diese Hilfsklasse den Thrad anstoßen?
Das bring mit aber leider nichts.
Meine Hauptklasse hat keine Ahnung wann es was zu tun gibt (ich lese im Thread Daten über die Indy-Komponente ein).

Ich habe es momentan so gelöst, das ich ein WaitForSingeObject(self.Handle, 20) verwende.

alzaimar 26. Apr 2006 06:49

Re: Frage zu Thread und Ciritical Section
 
Der Thread wird aber doch nicht ständig Daten einlesen, sondern muss auch warten, *bis* Daten vorhanden sind. Dann ist eben nicht das Hauptprogramm zuständig, den Thread anzustoßen, sondern Windows bzw. die Indy-Komponente. Die hat doch mit Sicherheit ein Event 'OnData', oder?
Es gibt nur sehr wenige Außnahmen, wo ein Thread wirklich nonstop rechnen muss: Bei aufwändigen Berechnungen etwa, oder bei Echtzeitspielen.

I/O ist doch gerade dafür geschaffen, im Hintergrund 'en passant' abgewickelt zu werden, denn die meiste Zeit wartet man doch sowieso, bis endlich mal wieder ein Byte vorbeihuscht.

Man muss sich unter Windows davon verabschieden, in der klassischen Art und Weise I/O zu programmieren (nämlich durch polling). Statt dessen sagt man Windows, wen und was es aufrufen soll, *wenn* etwas passiert, also wenn z.B. Daten angekommen sind. Auch wenn man sich auf ein 'Read' setzt, passiert im Hintergrund nichts anderes.

Die ICS-Komponenten von Francois Piette (www.overbyte.be) sind komplett auf Events aufgebaut und damit asynchron und einfach als Komponenten zu verwenden. Der Nachteil an der Sache ist dann aber, das man Zustandsautomaten programmieren muss. Bei der SMPT-Komponente (emails lesen) muss man das Ereignis 'OnGetData'. Dieser Event wird immer ausgelöst, wenn etwas vom EMail-Server zurückkommt. Man programmiert also nur, wie sich die Anwendung verhalten soll. Damit kann dann das Versenden einer EMail wirklich parallel zum Hauptprogramm erfolgen, ohne auch nur einen einzigen Thread geschrieben zu haben.


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