2009-05-22 18 views
5

Ich muss ein System von Arbeitern (als Threads dargestellt) und (mehrere) Warteschlangen erstellen. Einzelne Jobs warten in einer der Warteschlangen und warten auf einen Worker-Thread, um sie zu verarbeiten. Jeder Worker kann Jobs nur von einigen der Warteschlangen verarbeiten. Keine Warteschleife. C/C++, Pthreads, Standard POSIX.C++ - Threads und mehrere Warteschlangen

Das Problem für mich ist das „mehrere Warteschlangen“ Ding. Ich weiß, wie man das mit einer einzigen Warteschlange implementiert. Die Arbeiter müssen auf alle Warteschlangen warten, die sie verarbeiten können (auf ALLE warten).

Unter Windows würde ich WaitForMultipleObjects verwenden, aber dies muss Multi-Plattform sein.

Ich möchte keinen bestimmten Code dafür, nur einen Hinweis oder eine Beschreibung des Modells, das ich verwenden sollte. Danke im Voraus.

+0

Können Sie Boost überhaupt verwenden? – PiNoYBoY82

Antwort

4

Was können Sie tun, ist eine condition variable verwenden. Lassen Sie Ihre Worker-Threads auf eine Bedingungsvariable warten. Wenn ein Job zu einer der Jobwarteschlangen hinzugefügt wird, melden Sie die Bedingungsvariable. Wenn der Worker-Thread dann aufwacht, überprüft er die Warteschlangen, auf die er wartet. Wenn einer von ihnen einen Job hat, nimmt er diesen Job aus der Warteschlange. Andernfalls wird wieder auf die Zustandsvariable gewartet. Wenn Sie auf eine Bedingungsvariable warten, wird der Thread in den Ruhezustand versetzt, sodass keine CPU-Zeit verbraucht wird.

Natürlich sollten Sie alle Zugriffe auf die Jobwarteschlangen mit einem Mutex schützen (z. B. pthread_mutex_t).

+0

Gute Idee, aber dadurch werden alle Worker-Threads aktiviert, wenn ein Job in eine leere Warteschlange hinzugefügt wird. Ich nehme an, ich werde es trotzdem tun, aber gibt es eine Möglichkeit, nur den "richtigen" Thread aufzuwecken (und im Idealfall nur einen von allen richtigen Threads)? –

+0

pthread_cond_signal() aktiviert mindestens einen Thread, der auf die Bedingungsvariable wartet, während pthread_cond_broadcast() alle Threads aktiviert. In der Theorie sollte pthread_cond_signal() nur einen Thread die meiste Zeit aufwachen, aber ich weiß nicht, ob das in der Praxis wahr ist oder nicht. –

+0

Aber in Ihrer Lösung muss * ich * alle Threads aktivieren, da sich ein Job möglicherweise in einer Warteschlange befindet, die der * one * -Working nicht verarbeitet. –

1

Wenn es nicht zu viele Arbeiter für jede Warteschlange sind, könnten Sie eine Bedingungsvariable für jeden Arbeitnehmer machen.

0

Was ich tun würde, ist die Verwendung boost :: asio Daten in die Warteschlange einzureihen, so dass Ihre mehrere Threads gehen an es haben kann. Sie können einen Verweis über den Befehl post an die Warteschlange übergeben und den Thread entsprechend verarbeiten lassen.

0

Anstatt eine separate Sperre für jede Warteschlange zu haben, warum nicht eine Sperre für alle Warteschlangen haben?

  1. Warten auf das Schloss
  2. Holen das Schloss
  3. Dequeue von welcher Warteschlange
  4. die Sperre
  5. Verfahren das Aus der Warteschleife angenommene Punkt
  6. Goto Schritt 1

Unter der Annahme, dass die Aussperrung nimmt nur eine vernachlässigbare Zeit in Anspruch (so wird die Sperre nur für eine vernachlässigbare Zeit gehalten) Möglicherweise müssen Sie nicht mehr als eine Sperre verwenden.

+0

Ich glaube nicht, dass das funktionieren wird. Ein Worker verarbeitet nur Jobs aus einer bestimmten Warteschlange. Wenn nur ein Job in einer "schlechten" Warteschlange vorhanden ist, ist der Mitarbeiter beschäftigt und wartet, bis der andere Mitarbeiter den Job angenommen hat. –

0

Sie könnten so etwas tun: Jedem Job ist eine "Warteschlange" zugeordnet. ZB:

Angenommen, Sie haben 2 Warteschlangen. Ihre Jobs könnten sagen:

job[0].queue = 1; /* That job is in queue 1 */ 
job[1].queue = 1; 
job[2].queue = 2; /* this job is in queue 2 */ 
... 
etc 

Also dann haben Sie Ihre "Tasche von Threads". Ein Thread wählt einfach einen Job aus - sagen wir, Job [2]. Wenn dieser Thread nur Jobs aus der Warteschlange 1 verarbeiten darf, stellt er diesen Job wieder in die Bereit-Warteschlange und wählt einen anderen Job aus.

So weiß jeder Thread, welche Warteschlangen er verarbeiten darf, und wenn er einen Job auswählt, stellt er sicher, dass das Feld "Queue" des Jobs übereinstimmt. Wenn dies nicht der Fall ist, wählt es einen anderen Job.

(Dies ist in vielerlei Hinsicht, wie Prozessplanung in Linux auf mehreren Kernen funktioniert. Jeder Prozess hat eine Bitmaske, welche Prozessoren es erlaubt zu laufen, und dann der Prozessor stellt sicher, es ist "erlaubt", diesen Prozess auszuführen bevor dies zu tun)

5

Wie wäre.

  • alle worker-Threads auf einem Semaphor warten
  • , wenn etwas in die Warteschlange hinzugefügt wird, wird die Semaphore erhöht, was ein einzelner Thread
  • wacht der Faden chec ks die Warteschlangen es interessiert ist, verarbeitet eine von ihnen und geht zurück auf die Semaphore zu warten

Sie zusätzliche Mutex müssen (es) zu tatsächlichen Steuerung lesen & zu den Warteschlangen schreibt.

+1

+1 Ich werde mit Neil auf diesem gehen :) – ralphtheninja

0

Ich habe kürzlich darüber nachgedacht und die einzige Idee, die ich bekommen könnte, ist (vorausgesetzt, dass Sie thread-sichere Warteschlangen haben), nur mehrere Threads für eine einzige Warteschlange zu haben.

Sie können dann einen oder mehrere Arbeit produzierende Threads haben, die Jobs zu einer einzelnen Warteschlange und einem oder mehreren Worker-Threads hinzufügen, die in der Warteschlange blockieren, bis sie etwas zur Verarbeitung finden.

Wenn Sie mehrere Warteschlangen haben, die von mehreren Worker-Threads abgefragt werden müssen, besteht die Lösung darin, für jede Warteschlange und eine zusätzliche Warteschlange einen zusätzlichen Thread hinzuzufügen. Die zusätzlichen Threads blockieren jeweils für ihre eigene Warteschlange, leiten Jobs jedoch einfach an die zusätzliche Warteschlange weiter. Jetzt wird der vorhandene Arbeitsthread wieder in einer einzelnen Warteschlange blockiert.

Verwandte Themen