Autor Beitrag
Gausi
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: Di 13.04.10 18:36 
Ich hab da eine kleine Verständnisfrage zu Semaphoren. Ich habe eine Workerthread-Klasse, die so aussieht:
ausblenden 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(Nil0, 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:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
procedure TCoverDownloadWorkerThread.StartWorking;
begin
    ReleaseSemaphore(fSemaphore, 1Nil);
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?
ausblenden 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

_________________
We are, we were and will not be.


Zuletzt bearbeitet von Gausi am Di 13.04.10 21:06, insgesamt 2-mal bearbeitet
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Di 13.04.10 19:14 
user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
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 ;) .
ausblenden volle Höhe 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;

{ TMyThread }

constructor TMyThread.Create;
begin
  inherited Create(True);
  fSemaphore := CreateSemaphore(nil0, 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, 1nil);
    Sleep(1000);
  end;
end.

_________________
>λ=
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: 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
ausblenden 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:

_________________
We are, we were and will not be.
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: Di 13.04.10 19:34 
Eigentlich nimmt man für diesen Zweck ja Events :roll:

user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
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.

user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
und kann man das ggf. abstellen, falls das hier nicht sinnvoll ist?

Ich würde also sagen, nein.

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: 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?

_________________
We are, we were and will not be.
Narses
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Administrator
Beiträge: 10183
Erhaltene Danke: 1256

W10ent
TP3 .. D7pro .. D10.2CE
BeitragVerfasst: Di 13.04.10 19:52 
Moin!

Du suchst nicht sowas, oder? :gruebel:

cu
Narses

_________________
There are 10 types of people - those who understand binary and those who don´t.
Martok
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 3661
Erhaltene Danke: 604

Win 8.1, Win 10 x64
Pascal: Lazarus Snapshot, Delphi 7,2007; PHP, JS: WebStorm
BeitragVerfasst: 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.

user profile iconGausi hat folgendes geschrieben Zum zitierten Posting springen:
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.

ausblenden 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:
//Von außen:
  FFeedEvent:= TEvent.Create(nil, true, false,'');
  FFeed:= TWOFeed.Create(Self, FFeedEvent);


// wo anders:
  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.

_________________
"The phoenix's price isn't inevitable. It's not part of some deep balance built into the universe. It's just the parts of the game where you haven't figured out yet how to cheat."
Gausi Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 8548
Erhaltene Danke: 477

Windows 7, Windows 10
D7 PE, Delphi XE3 Prof, Delphi 10.3 CE
BeitragVerfasst: 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

_________________
We are, we were and will not be.