Entwickler-Ecke

Windows API - 100 gleiche Threads starten


maxk - Mi 18.06.03 06:51
Titel: 100 gleiche Threads starten
Hi,
ich versuche mit folgendem Code 100 Threads zu erstellen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
var Threads:array[1..100of TCalcThread;
    a:integer;
begin
 repeat
  for a:=1 to 100 do if Threads[a]=nil then
   Threads[a]:=TCalcThread.CreateThread(a);
 until (Application.Terminated) or (ButtonAbbrechenClicked);
end;
Der Windows Task-Manager zeigt aber nur 5 Threads an. Sind alle 5 Threads beendet, wird die Schleife verlassen (auch wenn keine der Bedingugen erfüllt ist). Gibt es so eine Art MaxThread Schalter oder eine andere Erkärung?

maxk


mars - Mi 18.06.03 08:37

Ich weiss nicht, ob es eine Beschränkung gibt, aber ich mal irgendwo gelesen, dass Borland für heutige Rechner (oder warens ältere?) höchstens 16 empfiehlt. Darüber sei Schluss.


Delete - Mi 18.06.03 09:56

Nur mal so als Denkanstoß: 100 Threads starten, ist gleichbedeutend mit dem Start von 100 Singlethread Programmen, wie Notepad oder Paint. Denkl mal drüber nach. :wink:


AndyB - Mi 18.06.03 12:49

Luckie hat folgendes geschrieben:
Nur mal so als Denkanstoß: 100 Threads starten, ist gleichbedeutend mit dem Start von 100 Singlethread Programmen, wie Notepad oder Paint. :wink:

Nicht ganz, denn für einen Prozess kommt noch etwas mehr Overhead dazu. Aber das Prinzip stimmt.


Delete - Mi 18.06.03 13:34

Auf die Details wollte ich jetzt nicht eingehen. Ich wollte ihm nur mal deutlich machen, was er da überhaupt vor hat.


maxk - Mi 18.06.03 18:26

Starte ich die Threads 150 Mal, so sehe ich im Taskmanager 7 Threads. Ist das hilfreich?


Delete - Mi 18.06.03 18:30

Dann würde ich mal behaupten, er wurde auch nur 7 mal gestartet. Ansonsten kuck mal auf deine Signatur.


maxk - Mi 18.06.03 18:38

:rofl: :rofl: :rofl:


AndyB - Mi 18.06.03 18:41

Den obige Code hast du hier direkt im Forum programmiert. Denn so wie der aussieht, funktioniert er in keinem Fall, da er schon beim Syntax Check hängenbleibt.


maxk - Mi 18.06.03 18:51

Warscheinlich spielst du auf TCalcThread.CreateThread an. TCalcThread ist selbstgecoded (class TThread, was auch nicht richtig funktioniert).


AndyB - Mi 18.06.03 18:56

Weniger. Denn das ist möglich. Jedoch meckert der Compiler bei "Treads", da dort das "h" fehlt.

Also bitte den original Code posten, denn mit "frei erfundenem" Code lässt sich ein Fehler recht schwer finden.


maxk - Mi 18.06.03 21:00

Entschuldigung für die Anspielung :oops:
Den Code habe ich mit der Hand abgetippt (weiß der Teufel warum). Den Fehler habe ich korrigiert.
Das nächste Mal kopiere ich den Code :wink:


AndyB - Mi 18.06.03 21:45

Was macht den CreateThread genau? Setzt es den ACreateSuspended Parameter von Create auf True oder etwa in einer Abhängigkeit von etwas?

Wie rufst du den Vorfahr-Create-Konstruktor auf? Etwa mit inherited Create? Hast du da auch einen eigenen Create-Konstruktor erstellt?


maxk - Do 19.06.03 18:37

Ich erstelle mit inherited Create(True);, mache ein paar Variablenzuweisungen à la Nr:=a; und FreeOnTerminate:=True und setze schließlich Suspended:=False;


AndyB - Do 19.06.03 22:07

Ich habe mir dein Codebeispiel gerade noch einmal angeschaut. Du verwendest da ein statisches Array, das auf dem Stack liegt. Dieses musst du im Gegensatz zu dynamischen Arrays vorher initialisieren. Denn so wie es da oben steht, enthalten die Elemente des Arrays die Daten, die zufällig auf dem Stack liegen. Und diese zufälligen Werte sind nicht unbeding nil, womit deine if Threads[a] = nil Abfrage sehr häufig scheitert und kein Thread erstellt wird.

Was bei deinem Code fehlt ist folgendes:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
var
  Threads:array[1..100of TCalcThread; 
  a:integer; 
begin 
  FillChar(Threads, SizeOf(Threads), 0); // <<-- initialisieren

  repeat 
    for a:=1 to 100 do 
      if Threads[a]=nil then 
       Threads[a]:=TCalcThread.CreateThread(a); 
  until (Application.Terminated) or (ButtonAbbrechenClicked); 
end;


Wie greift eigentlich TCalcThread auf Threads[] zu um es wieder auf nil zu setzen. Den Index a hat TCalcThread ja, aber auf das lokale Array kann es nie zugreifen.


maxk - Fr 20.06.03 09:47

Danke, ich werdes es versuchen, wenn ich wieder zu Hause bin...
Das nil erfolgt automatisch durch FreeOnTerminate:=True. Bin aber wie gesagt noch nicht dazu gekommen, es auszutesten :cry:


AndyB - Fr 20.06.03 19:52

FreeOnTerminate := True verändert noch lange nicht den Eintrag im Threads-Array. Das musst du schon im Destruktor des Threads machen. Nur hat der keinen Zugriff auf das Array, weil der Index alleine nicht ausreicht um auf ein lokales Array zuzugreifen.


maxk - Sa 21.06.03 10:07

AndyB hat folgendes geschrieben:
weil der Index alleine nicht ausreicht um auf ein lokales Array zuzugreifen.
Den Index brauche ich, um auf Dateien zuzugreifen, welche im Format Calc_0,Calc_1,usw. vorliegen. Das mit dem FreeOnTerminate wusste ich aber nicht. Wäre es möglich im Destructor zu schreiben:

Delphi-Quelltext
1:
2:
inherited Destroy;
Self:=nil;
Trotzdem erklärt das aber alles nicht, warum nicht 100 Threads erstellt werden...


AndyB - Sa 21.06.03 10:17

maxk hat folgendes geschrieben:
Wäre es möglich im Destructor zu schreiben:

Delphi-Quelltext
1:
2:
inherited Destroy;
Self:=nil;
Trotzdem erklärt das aber alles nicht, warum nicht 100 Threads erstellt werden...

Nein. Damit setzt du nur eine Kopie des Zeigers auf nil. Der Zeiger besteht immernoch im Threads-Array. Du musst schon das Threads-Array selbst verändern.
Eine Möglichkeit wäre es folgendermaßen zu lösen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
PCalcThread = ^TCalcThread; // Zeiger auf Zeiger
...
  Threads[a] := TCalcThread(a, @Threads[a]);
...


constructor TCalcThread.CreateThread(a: Integer; AThreadVariable: PThread);
begin
  FThreadVariable := AThreadVariable;
  // Felder initialisieren 
  // ...
  Create(False); // direkt starten (wenn du Create nicht überschrieben hast, musst du auch kein inherited schreiben)
end;

destructor TCalcThread.Destroy;
begin
  FThreadVariable^ := nil// Array-Eintrag auf nil setzen
  inherited Destroy;
end;


maxk - So 22.06.03 15:50

Danke, ich werde es probieren, wenn mein Delphi-Notebook aus der Reperatur zurück ist.

maxk