![]() |
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; |
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; |
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. |
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 ._. |
Re: Frage zu Thread und Ciritical Section
Zitat:
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 |
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. |
Re: Frage zu Thread und Ciritical Section
Hallo,
hmm... Zitat:
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 |
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:
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).
Procedure TMyThread.Execute;
Begin While Not Terminated Do Begin WaitForSomethingToDoOrTerminated; If SomethingToDo Then DoIt; End; End; 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. |
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. |
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 ( ![]() |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:43 Uhr. |
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