Forum: PC-Programmierung C++11: Anzahl laufender Threads begrenzen


von Maxim (maxim) Benutzerseite


Lesenswert?

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.
1
thread *iterateStepZ = new thread[K];
2
for(int k = 0; k < K; k++) {
3
  new(iterateStepZ + k) thread(threadIterate, k, K, b, n, E, Z, ZNext);
4
}
5
    
6
for(int k = 0; k < K; k++) {
7
  iterateStepZ[k].join();
8
}

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?

von Dominik Thalhammer (Gast)


Lesenswert?

Nein, so weit ich weis geht das nicht, allerdings kannst du das doch 
ganz leicht selbst machen.

von Klaus W. (mfgkw)


Lesenswert?

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.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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.

von Klaus W. (mfgkw)


Lesenswert?

"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 :-)

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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...

von Stephan B. (matrixstorm)


Lesenswert?

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

von Stephan B. (matrixstorm)


Lesenswert?

Ja, oder OpenMP verwenden.

Da kann man den Workload auch Gruppieren, ohne das man sich explizit um 
Threaderstellung kuemmern muss.

MfG

von Rolf Magnus (Gast)


Lesenswert?

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.

von (prx) A. K. (prx)


Lesenswert?

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.

von Maxim (Gast)


Lesenswert?

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!

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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!

von Rolf Magnus (Gast)


Lesenswert?

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...

von Peter (Gast)


Lesenswert?

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?
1
new(iterateStepZ + k) thread(threadIterate, k, K, b, n, E, Z, ZNext);

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.