2012-05-04 4 views
8

Ich programmiere in C++, aber ich verwende nur pthread.h, keine Boost oder C++ 11 Threads.Wie sollte ein Thread-Pool in C implementiert werden?

Also versuche ich Threads zu verwenden, aber basierend auf einer meiner vorherigen Fragen (link), scheint dies nicht machbar, da Threads direkt nach Abschluss der Aufgabe beendet werden, und einer der häufigsten Gründe, einen Thread zu verwenden- Die Poolimplementierung soll den Thread-Erstellungsaufwand reduzieren, indem diese Threads für mehrere Tasks wiederverwendet werden.

Also ist die einzige andere Möglichkeit, dies in C zu implementieren, um fork() zu verwenden, und eine Pipe von den Haupt- zu untergeordneten Prozessen zu erstellen? Oder gibt es eine Möglichkeit, eine Verbindung zwischen Threads und ihren Eltern aufzubauen, von denen ich nichts weiß?

Vielen Dank im Voraus!

+0

Hiding Thread-Erzeugung und mit etwas wake-up Ereignisse eine Warteschlange von Jobs (Funktion + Objekt) mit sollte es tun . Suchst du nach einem bestimmten Verhalten? –

+2

Entscheiden Sie, ob Sie eine C- oder C++ - Lösung möchten. Ob die zugrunde liegende Bibliothek Pthreads ist (d. H. Nur C), ist viel weniger wichtig als die Sprache, für die Sie den Thread-Pool bereitstellen möchten. –

+0

.. und wählen Sie dann C++ –

Antwort

6

Ja, Sie können einen thread-safe queue zwischen den Threads erstellen. Dann werden die Threads im Pool in einer Schleife sitzen und ein Element aus der Warteschlange abrufen, was auch immer es benötigt, und dann zurückgehen und ein anderes holen.

Das ist in C++ in der Regel etwas einfacher/einfacher, weil es ein wenig einfacher ist, sich auf einige der Schnittstellen zu einigen (z. B. operator(), um den Code für eine Aufgabe auszuführen), aber auf einer grundlegenden Ebene können Sie das Gleiche tun Dinge in C (zB jede task Struktur, die Sie in die Warteschlange setzen, enthält einen Zeiger auf eine Funktion, um die Arbeit für diese Aufgabe auszuführen).

In Ihrem Fall, da Sie C++ verwenden, ist es wahrscheinlich einfacher, eine Überladung von operator() zu verwenden, um die Arbeit zu erledigen. Der Rest der task Struktur (oder was auch immer Sie wählen, um es zu nennen) enthält alle erforderlichen Daten usw.

+0

Idealerweise müsste die Warteschlange threadsicher sein und einen Semaphor mit einem Maximalwert der maximalen Zahl verwenden von Threads, die ich spawnen werde, oder? Diese Implementierung scheint ein bisschen dreckig zu sein ... Ich fühle mich nie richtig, Daten/Container "in Sichtweite" zu setzen, nicht eingekapselt von einer Klasse. Deshalb habe ich nach einer master-child_thread-Pipe-Implementierung gefragt –

+0

Ist der Aufwand für eine Eltern-Kind_PROCESS-Pipe wert Datenkapselung? –

+0

@ K-RAN: Die eine, die ich verlinkt habe (bis zum "letzten Code" scrollen) * ist * in einer Klasse gekapselt. –

3

Vom POSIX standard:

int pthread_create(pthread_t *restrict thread, 
    const pthread_attr_t *restrict attr, 
    void *(*start_routine)(void*), void *restrict arg); 

(...), um den Faden erzeugt wird, mit start_routinearg als einziges Argument ausgeführt wird.

Also, sollten Sie ein paar Fäden mit dieser Funktion erstellen und haben sie alle eine Funktion ausführen, die so etwas wie

void *consumer(void *arg) 
{ 
    WorkQueue *queue = static_cast<WorkQueue *>(arg); 

    for (task in queue) { 
     if (task == STOP_WORKING) 
      break; 
     do work; 
    } 
    return WHATEVER; 
} 

(Am Ende der Eingabe geht, schieben nSTOP_WORKING Artikel in die Warteschlange, wo n die Anzahl der Gewindegänge ist.)

Wohlgemerkt, eine sehr niedrige Ebene pThreads API ist, die sehr wenig Typsicherheit bietet (alle Daten als void p weitergegeben Ointern). Wenn Sie versuchen, CPU-intensive Aufgaben zu parallelisieren, sollten Sie stattdessen OpenMP betrachten.

2

'scheint nicht machbar, da Threads direkt nach Abschluss der Aufgabe beenden' was ??

for(;;){ 
    Task *myTask=theCommonProducerConsumerQueue->pop(); 
    myTask->run(); 
} 

.. nie zurückgeben, tatsächlich, nie zurückkehren.

+0

Ich habe nie vorher darüber nachgedacht, noch wusste ich über Pthread Schlaf Methoden; Mein Verständnis von Threads davor war, dass sie One-Shot-Dinge sind. –

-1

http://people.clarkson.edu/~jmatthew/cs644.archive/cs644.fa2001/proj/locksmith/code/ExampleTest/threadpool.c

I verwendet Google vor ein paar Monaten sollten Sie es versuchen.

Edit: es scheint vielleicht wollen Sie eine Gruppe statt. Ich war in der Lage, einen mit einigen kleinen Änderungen des oben genannten zu schaffen, so dass der Arbeiter keine Arbeit ausführte, sondern sich nur den Fäden anschloss.

+0

Haben Sie eine Idee, wie Sie diesen Threadpool in die Event-Bibliothek wie Libevent integrieren? Es scheint eine eigene Endlosschleife zu haben, die auf die Aufgabe für den Thread wartet. –

2

Sie können es hilfreich finden, um the source code for libdispatch zu betrachten, die die Grundlage für Apples Grand Central Dispatch ist und Thread-Pools verwendet.

+1

Whoa, interessant. Vielen Dank! –

1

Ich würde vorschlagen, Threaded Building Blocks von Intel zu Arbeits-Queue/Threadpool wie Aufgaben zu erreichen. Ein ziemlich konstruiertes Beispiel TBB mit 3,0:

class PoorExampleTask : public tbb::task { 
    PoorExampleTask(int foo, tbb::concurrent_queue<float>& results) 
    : _bar(foo), _results(results) 
    { } 

    tbb::task* execute() { 
     _results.push(pow(2.0, foo)); 
     return NULL; 
    } 

private: 
    int _bar; 
    tbb::concurrent_queue<float>& _results; 
} 

wie später verwendet, um:

tbb::concurrent_queue<float> powers; 
for (int ww = 0; ww < LotsOfWork; ++ww) { 
    PoorExampleTask* tt 
     = new (tbb::task::allocate_root()) PoorExampleTask(ww, powers); 
    tbb::task::enqueue(*tt); 
} 
Verwandte Themen