Entwickler-Ecke
Windows API - Semaphoren und Threads (und Events)
Gausi - Di 13.04.10 18:36
Titel: Semaphoren und Threads (und Events)
Ich hab da eine kleine Verständnisfrage zu Semaphoren. Ich habe eine Workerthread-Klasse, die so aussieht:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26:
| type TCoverDownloadWorkerThread = class(TThread) private fSemaphore: THandle; end;
constructor TCoverDownloadWorkerThread.Create; begin fSemaphore := CreateSemaphore(Nil, 0, maxInt, Nil); end;
procedure TCoverDownloadWorkerThread.Execute; begin While Not Terminated do begin if (WaitforSingleObject(fSemaphore, 1000) = WAIT_OBJECT_0) then if not Terminated then begin machwas; end; end; end; |
Ich erzeuge also eine Semaphore, und warte darauf, dass da was passiert, bevor der eigentliche Thread anfängt zu arbeiten. Wenn was zu tun ist, rufe ich von der VCL aus das auf:
Delphi-Quelltext
1: 2: 3: 4:
| procedure TCoverDownloadWorkerThread.StartWorking; begin ReleaseSemaphore(fSemaphore, 1, Nil); end; |
Von meinem Verständnis her habe ich damit einen Thread, der schön im Hintergrund schlummert, bis er angestoßen wird oder terminieren soll.
Jetzt sieht das im Ereignisprotokoll aber so aus, als würden da ständig neue Threads laufen. Mach ich da was falsch, oder ist das normal so? D.h. die ID des Worker-Threads wechselt bei so einer Anwendung?
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| Thread-Start: Thread-ID: 4064. Prozess nemp.exe (3720) Thread-Ende: Thread-ID: 4064. Prozess nemp.exe (3720) Thread-Start: Thread-ID: 3012. Prozess nemp.exe (3720) Thread-Ende: Thread-ID: 3012. Prozess nemp.exe (3720) Thread-Start: Thread-ID: 1204. Prozess nemp.exe (3720) Thread-Ende: Thread-ID: 1204. Prozess nemp.exe (3720) Thread-Start: Thread-ID: 1364. Prozess nemp.exe (3720) Thread-Ende: Thread-ID: 1364. Prozess nemp.exe (3720) Thread-Start: Thread-ID: 3552. Prozess nemp.exe (3720) Thread-Ende: Thread-ID: 3552. Prozess nemp.exe (3720) Thread-Start: Thread-ID: 196. Prozess nemp.exe (3720) Thread-Ende: Thread-ID: 196. Prozess nemp.exe (3720) Thread-Start: Thread-ID: 2376. Prozess nemp.exe (3720) Thread-Ende: Thread-ID: 2376. Prozess nemp.exe (3720) // für jeden Job ein Thread, immer einer nach dem anderen |
Kha - Di 13.04.10 19:14
Gausi hat folgendes geschrieben : |
Von meinem Verständnis her habe ich damit einen Thread, der schön im Hintergrund schlummert, bis er angestoßen wird oder terminieren soll. |
So würde ich es doch auch sehen. Von daher ist es halbwegs beruhigend, dass uns wenigstens der folgende Code Recht gibt ;) .
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40:
| program Project2;
{$APPTYPE CONSOLE}
uses SysUtils, Classes, Windows;
type TMyThread = class(TThread) public fSemaphore : THandle; constructor Create; protected procedure Execute; override; end;
constructor TMyThread.Create; begin inherited Create(True); fSemaphore := CreateSemaphore(nil, 0, MaxInt, nil); end;
procedure TMyThread.Execute; begin inherited; while WaitForSingleObject(fSemaphore, INFINITE) = WAIT_OBJECT_0 do Writeln('a'); end;
var t : TMyThread; begin t := TMyThread.Create; t.Start; while True do begin ReleaseSemaphore(t.fSemaphore, 1, nil); Sleep(1000); end; end. |
Gausi - Di 13.04.10 19:31
Ok, der Code verhält sich bei mir auch nicht so. :D
Nachdem ich mal diese beiden Zeilen auskommentiert habe
Delphi-Quelltext
1: 2: 3:
| XMLData := fIDHttp.Get(url); fIDHttp.Get(BestCoverURL, DataStream); |
Ist das auch im Originalcode so.
Frage also: warum machen die Indys das so, und kann man das ggf. abstellen, falls das hier nicht sinnvoll ist? Der Download läuft ja schon in einem Nebenthread, da muss doch nicht noch einer gestartet werden. :gruebel:
Martok - Di 13.04.10 19:34
Eigentlich nimmt man für diesen Zweck ja Events :roll:
Gausi hat folgendes geschrieben : |
Der Download läuft ja schon in einem Nebenthread, da muss doch nicht noch einer gestartet werden. :gruebel: |
Doch. Irgendwo muss ja der MessageLoop hin, mit dem die Indies das schöne Nachrichtenbasierte WSA-Gedöns synchron machen.
Gausi hat folgendes geschrieben : |
und kann man das ggf. abstellen, falls das hier nicht sinnvoll ist? |
Ich würde also sagen, nein.
Gausi - Di 13.04.10 19:48
Ok, dann ist das wohl so in Ordnung. :)
Zu den Events: Wie würde da denn das Grundgerüst aussehen? Was ich sonst in der Richtung Workerthread gesehen habe, arbeitet iirc auch mit einer Semaphore. Und der Delphi-TThread hat doch keine Nachrichtenschleife, in die ich was einhängen könnte, oder?
Martok - Di 13.04.10 20:03
@Narses: nein, meine ich nicht. Ich meine die Synchronisationsobjekte "Event". Obwohl man sicher auch TMessageThread für die Anwendung nehmen könnte... wäre zu überlegen.
Gausi hat folgendes geschrieben : |
Zu den Events: Wie würde da denn das Grundgerüst aussehen? |
Fast genauso, nur dass man statt CreateSemaphore CreateEvent verwendet.
Und dann später SetEvent oder PulseEvent. Code hab ich auch irgendwo, ich kopier mal was raus... ah, okay, da war ein VCL-Fan am Werk. Unit SyncObjs.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
| FFeedEvent:= TEvent.Create(nil, true, false,''); FFeed:= TWOFeed.Create(Self, FFeedEvent);
if NochBufferDa then Verarbeiten; else begin FFeedEvent.SetEvent; exit; end;
procedure TWOFeed.Execute; var b: integer; begin b:= 0; while not Terminated do begin FEvent.WaitFor(100); FEvent.ResetEvent; try FOwner.Thread_SendFunc(b); except raise; end; end; end; |
Also quasi das Gleiche. Nur das Events
wesentlich schneller sind, was die Zeit von SetEvent bis zum Zurückkehren von WaitFor* betrifft. Liegt unter anderem da dran, dass sie für dieses Thema gemacht sind.
Und wir reden hier IIRC von Mikrosekunden vs. Millisekunden.
Gausi - Di 13.04.10 20:17
Ah, ok. Wieder was gelernt. :D
Den MessageThread behalte ich mal im Hinterkopf, und diese Form der Events auch. Das sind also nicht die Events, die man an den Komponenten kennt, sondern globale Dinger, richtig?
Aber um Geschwindigkeiten mach ich mir hier aber keine Gedanken. Erstens soll der Thread was runterladen (erst eine kleine REST-Anfrage, dann ein kleines Bild, im Schnitt 50-100 kb). Der Flaschenhals liegt also ganz woanders. Und zweitens darf ich das sowieso nur maximal fünf mal pro Sekunde machen, sonst schimpfen die bei LastFM. ;-)
Aber ich probier das mal mit den Events aus, das scheinen ja nur ein paar kleine Änderungen zu sein, die ich da machen muss.
Edit: ich müsste dann ein if FEvent.WaitFor(100)=wrSignaled then... einbauen, wenn nur dann etwas getan werden soll, wenn das Event vorher ausgelöst wurde, oder?
Edit2: Ok, mit Events geht das genauso gut. Und wenn die für sowas da sind, dann lass ich das jetzt auch so. :D
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!