2010-11-24 3 views
1

Ich implementiere einen Thread-Pool. Die Arbeit, die von jedem Thread benötigt wird, ist 1-10 Sekunden CPU, also bin ich glücklich, einen traditionellen Thread-Pool mit Arbeitern zu haben, oder ich bin glücklich, einen neuen Thread für jede Arbeitseinheit zu erstellen. Es ist egal.Warten, bis einer von mehreren Threads beendet ist?

Ich mag würde einen Weg für die Master-Steuer Thread müssen zu wissen, wenn einer der N-Worker-Threads ihre Arbeit beendet und ist für mehr (oder seine Zeit, eine andere zu beginnen) bereit. Ich habe pthread_join und pthread_cond_wait angeschaut. Es scheint keinen Weg zu geben, auf einen von N zu warten. Also dachte ich darüber nach, dass der Master-Thread eine Variable hat, die er benutzt, um schlafen zu gehen und die Arbeiter wach zu machen. Dies scheint zu funktionieren, wenn die Arbeiter nicht sterben. Wenn sie jedoch sterben, gibt es ein Fenster zwischen der Zeit, in der der Arbeiter den Controller aufweckt, und der Zeit, in der er stirbt, mit der ich nicht umgehen möchte.

Ich habe Intels TBB angeschaut, aber es sieht viel komplizierter aus, als ich brauche.

Gibt es eine einfache Äquivalent in PTHREADS zu WaitForMultipleObjects in Microsoft Windows?

+1

ich dies als C markiert, können Sie sich frei, es zu ändern, wenn dies nicht der Fall ist. –

+1

haben Sie Looping (N) für Pthread_join versucht. http://opengroup.org/onlinepubs/007908799/xsh/pthread_join.html –

+0

Ich stimme small_ticket zu. Warum kann das Schleifen für n pthread_joins nicht funktionieren? – Jay

Antwort

3

Dies ist ein relativ einfacher Anwendungsfall für Zustandsvariablen.

Sie haben eine ganzzahlige Anzahl der aktiven Arbeitselemente, die durch Mutex geschützt sind. Verfügen Sie außerdem über zwei Bedingungsvariablen, eine für die Signalisierung der Worker-Threads, die in einer Warteschlange verfügbar sind, und die andere, um dem Hauptthread zu signalisieren, dass ein Thread beendet wurde. Etwas wie:

main: 
    set freethreads to numthreads 
    init mutex M, condvars TOMAIN and TOWORKER 
    start N worker threads 
    while true: 
     wait for work item 
     claim M 
     while freethreads == 0: 
      cond-wait TOMAIN, M 
     put work item in queue 
     decrement freethreads 
     cond-signal TOWORKER 
     release M 

worker: 
    init 
    while true: 
     claim M 
     while no work in queue: 
      cond-wait TOWORKER, M 
     get work to local storage 
     release M 
     do work 
     claim M 
     increment freethreads 
     cond-signal TOMAIN 
     release M 

Beachten Sie, dass die Schleifen für immer ausgeführt werden. In Wirklichkeit würde es Signale geben, die dazu führten, dass sie beendet wurden und Beendigungs-/Bereinigungscode ausgeführt wurde.

+0

Das 'cond-signal' sollte * vor * Freigeben des Mutex erfolgen - andernfalls kann der Thread zwischen dem Testen des Zustandes und dem Warten signalisiert werden. – caf

+0

Ja, @caf, das habe ich bemerkt, als du deinen Kommentar geschrieben hast. Aktualisiert, um zu beheben. – paxdiablo

+0

Hallo. Das ist sehr interessant, aber ich denke, dass das, was Sie getan haben, ein grundlegender Zähl-Semaphor ist, oder? Ich mag die Verwendung von TOMAIN und TOWORKER. Der Hauptschlafraum schläft, bis einer der Arbeiter ihm eine Nachricht sendet, die anzeigt, dass Freethreads inkrementiert wurden und mehrere Worker auf cond-wait schlafen. Dies setzt auch voraus, dass es eine Warteschlange gibt? Meine Frage - hast du das wirklich versucht? Was passiert, wenn mehrere Arbeiter warten? Ich denke, dass das Cond-Signal sicherstellt, dass nur einer von ihnen aufwacht? – vy32

1

Haben Sie über einen Zählsemaphor nachgedacht?

+0

Yeah Semaphore sind die Standardlösung für diese Art von Sache. –

+0

Die Standard 1990er-Lösung. ;-) –

1

Aus der Sicht von architecturing, würde es in der Verantwortung der Thread-Pool sein. Synchronisation zwischen den Arbeitern und dem Pool sollte vorhanden sein.

pthread_mutex_lock() oder Zählen Semaphor (sem_wait() und sem_post()) ist für eine solche Synchronisation gut. Eine Möglichkeit, das zu tun kann, wie dargestellt werden:

  1. die Pool init ist das Zählen Semaphore durch den Aufruf: sem_init (p_to_sem_t, 0, int n);
  2. n Arbeiter erwerben den Semaphor durch Aufruf von: sem_wait();
  3. Der Pool wartet auf die Arbeiter, die zurückkommen, indem sie aufrufen: sem_wait();
  4. Der Pool überprüft die Semaphorzählung, um zu sehen, ob alle Mitarbeiter geparkt sind.
  5. Worker geben ihre Sperre beim Beenden durch Aufruf von sem_post();
+0

Wenn Sie darauf warten, dass einer von mehreren Arbeitern zurückkommt, sollte Schritt-4 aus dem Verfahren entfernt werden. –

+0

Das scheint sehr einfach und elegant. Ich wusste ehrlich gesagt nichts über die Datei . Ich habe gerade nach gesucht. Gibt es einen einfachen Weg zu wissen, * welche * der Arbeiter fertig waren, oder muss ich ein separates Array verwalten, das das verfolgt? – vy32

+0

Bei einer zweiten Überlegung ist das Problem bei diesem Ansatz, dass der Haupt-Thread dann herausfinden muss, welcher zum Zweck der Arbeit erwacht ist ... – vy32