Problem: Eine Funktion muss K-mal mit verschiedenen Parametern
aufgerufen werden. Da die Funktion viel CPU-Zeit braucht, erstelle ich K
Threads in einer Schleife. In der darauf folgenden Schleife wird join()
für jeden Thread aufgerufen, so dass erst nachdem alle Threads fertig
sind, das Programm fortfahren kann.
Es funktioniert auch alles ganz gut. Ich würde nun gerne die Anzahl
gleichzeitig laufender Treads auf einen benutzerdefinierten Wert
begrenzen. Geht das irgendwie mit der Bibliothek thread aus C++11?
Stichwort Semaphore:
Über die kann eine Anzahl begrenzter Resourcen verwaltet werden, z.B.
10.
Wenn jeder Thread (von z.B. 30) beim Start nach der S. fragt und erst
losläuft, wenn er sie zugeteilt bekommt, können die 10 ersten gleich
loslegen; die anderen werden ausgebremst bis jeweils einer frei wird.
Klaus Wachtler schrieb:> Wenn jeder Thread (von z.B. 30) beim Start nach der S. fragt
Dann ist es aber ggf. schon zu spät, der Thread läuft ja bereits. Sowas
löst man idealerweise mit einem Threadpool, welchem nurnoch Tasks zum
abarbeiten übergeben werden.
"Laufen" ist ein dehnbarer Begriff.
Ein Thread, der auf eine Semaphore wartet, hat mich bisher noch nicht
gestört - es geht hier ja auch um die CPU-Zeit beim OP.
Wenn man keine wartenden Threads möchte, muß man halt bereits das
Starten des Threads mit einer S. blocken.
Was natürlich schnell eine gewisse Ähnlichkeit mit einem Threadpool
bekommt :-)
Klaus Wachtler schrieb:> Ein Thread, der auf eine Semaphore wartet, hat mich bisher noch nicht> gestört
Bei 30 Threads störts dich vielleicht nicht, aber bei 3000 eventuell
schon... Jeder Thread belegt ja (egal ob er was tut) auch immer etwas
Speicher.
Klaus Wachtler schrieb:> es geht hier ja auch um die CPU-Zeit beim OP
Wobei das doch abstrus ist... er startet Threads (dadurch erhöht sich ja
erst mal potentiell die Ausführungszeit) um danach auf diese zu
warten...
Wenn also k nicht sehr groß ist könnte er auch einfach alle starten un
den Rest dem BS überlassen.
Klaus Wachtler schrieb:> Wenn man keine wartenden Threads möchte
Könnte man das Join auch einfach alle X iterationen in der Schleife
durchführen, das spart dan auch noch Speicher für das Array was hier dan
unötig groß ist...
Hallo
Das Stichwort hier ist: Signale (Conditions)!
Alle Threads sharen mindestens einen Mutex, eine Condition und einen
Counter.
Der Masterthread (welche Threads bis zu einer bestimmten Grenze
erstellen soll) macht:
1) LOCK den Mutex
2) Arbeite Schleife ab, welche solange Threads erstellt und dabei den
Counter erhoeht, bis die Grenze erreicht ist.
3) Wenn die Grenze erreicht ist, warte auf CONDITION (was den Mutex
automatisch loest)
4) UNLOCK nach Schleifenende
Jeder Thread mach kurz vor seinem Ende:
1) LOCK den MUTEX
2) Verringere den Counter
3) Broadcast CONDITION
4) UNLOCK den MUTEX
MfG
Maxim S. schrieb:> Ich würde nun gerne die Anzahl> gleichzeitig laufender Treads auf einen benutzerdefinierten Wert> begrenzen. Geht das irgendwie mit der Bibliothek thread aus C++11?
Wenn es das gäbe, was würdest du denn erwarten, was passiert, wenn du
versuchst, einen Thread zu starten, obwohl die Grenze schon erreicht
ist?
Läubi .. schrieb:> Klaus Wachtler schrieb:>> Ein Thread, der auf eine Semaphore wartet, hat mich bisher noch nicht>> gestört>> Bei 30 Threads störts dich vielleicht nicht, aber bei 3000 eventuell> schon... Jeder Thread belegt ja (egal ob er was tut) auch immer etwas> Speicher.
Zumindest auf dem PC ist der Speicher doch eher belanglos. Selbst wenn
jeder Thread extrem übertriebene 1kB brauchen würde, wären es bei 3000
Threads gerade mal 3 MB, also nicht mal ein Promille des Speichers eines
mittelmäßig ausgestatteten Rechners.
> Klaus Wachtler schrieb:>> es geht hier ja auch um die CPU-Zeit beim OP>> Wobei das doch abstrus ist... er startet Threads (dadurch erhöht sich ja> erst mal potentiell die Ausführungszeit) um danach auf diese zu> warten...
Daran ändert sich aber nicht viel, wenn er die Threads nicht gleich,
sondern erst später startet. Um sich den Overhead des Threadstartens zu
sparen, sollte er dann nur die 30 Threads zu starten und immer
wiederverwenden, statt jedesmal zu zerstören und dann wieder neu zu
starten.
Rolf Magnus schrieb:> Zumindest auf dem PC ist der Speicher doch eher belanglos. Selbst wenn> jeder Thread extrem übertriebene 1kB brauchen würde,
Allein der vollständige Registerkontext eines aktuellen Prozessors
frisst bereits mehr als die Hälfte davon. Ausserdem hast du die Stacks
ausser Acht gelassen.
Rolf Magnus schrieb:> Maxim S. schrieb:>> Ich würde nun gerne die Anzahl>> gleichzeitig laufender Treads auf einen benutzerdefinierten Wert>> begrenzen. Geht das irgendwie mit der Bibliothek thread aus C++11?>> Wenn es das gäbe, was würdest du denn erwarten, was passiert, wenn du> versuchst, einen Thread zu starten, obwohl die Grenze schon erreicht> ist?
Z.B. würde dieser Thread in eine Warteschlange eingereiht und erst
gestartetn, wenn die Anzahl der laufenden Threads unter den
Schwellenwert sinkt und der Thread als nächstes in der Warteschlange
kommt.
Mit "laufender" Thread meine ich nicht einen, der gestartet wurde,
sondern einen, der CPU-Zeit verbraucht bzw. vom OS anfordert.
Ist es nicht so, dass bei zu vielen gleichzeitig laufenden Threads der
Overhead für die Verwaltung groß wird und dadurch die Effizienz sinkt?
Zum Wert K: Mehr als 100 sollte dieser in der Regel nicht werden. 1000
ist eine sehr sichere Obergenze.
Vielen Dank für Vorschläge und anregungen soweit!
Rolf Magnus schrieb:> Zumindest auf dem PC ist der Speicher doch eher belanglos. Selbst wenn> jeder Thread extrem übertriebene 1kB brauchen würde
1KB? Auf einem AVR vielleicht ;-) Unter linux kann das z.B. auch mal
eben 10 MB betragen, außerdem gibt es eine maximal Anzahl von Threads,
siehe z.B.:
http://stackoverflow.com/questions/5635362/max-thread-per-process-in-linux
und ratz fatz ist es vorbei mit dem Spaß ;-)
Maxim schrieb:> Ist es nicht so, dass
Don't optimize if you haven't profiled it!
A. K. schrieb:> Rolf Magnus schrieb:>> Zumindest auf dem PC ist der Speicher doch eher belanglos. Selbst wenn>> jeder Thread extrem übertriebene 1kB brauchen würde,>> Allein der vollständige Registerkontext eines aktuellen Prozessors> frisst bereits mehr als die Hälfte davon. Ausserdem hast du die Stacks> ausser Acht gelassen.
Ja, hast natürlich recht. Da hab ich totalen Unsinn geschrieben. Es war
eine anstrengende Woche...
Etwas OT, würde mich aber trotzdem interessieren: Warum genau rufst du
den Konstruktor per placement new ein zweites mal auf, wenn du einen
Thread starten willst?