2012-05-04 13 views
8

Sto programmando in C++, ma sto usando solo thread pthread.h, no boost o C++ 11.Come deve essere implementato un pool di thread in C?

Quindi sto cercando di utilizzare thread ma basato su una delle mie precedenti domande (link), questo non sembra fattibile poiché i thread terminano subito dopo il completamento del suo compito, e uno dei motivi più diffusi per usare un thread- L'implementazione del pool riduce il sovraccarico di creazione dei thread riutilizzando questi thread per più attività.

Quindi è l'unico altro modo per implementare questo in C per utilizzare fork() e creare un pipe dai processi principali a quelli secondari? O c'è un modo per impostare una pipe tra i thread e i loro genitori di cui non conosco?

Molte grazie in anticipo!

+0

creazione dei thread Nascondere ed avendo una coda di posti di lavoro (funzione + oggetto) con qualche evento di wake-up dovrebbe farlo . Stai cercando un comportamento specifico? –

+2

Decidere se si desidera una soluzione C o C++. Se la libreria sottostante è pthreads (vale a dire solo C) è molto meno importante della lingua per la quale si desidera fornire il pool di thread. –

+0

.. e quindi scegli C++ –

risposta

6

Sì, è possibile creare uno thread-safe queue tra i thread. Quindi i thread nella piscina si posizioneranno in un ciclo recuperando un elemento dalla coda, eseguendo qualsiasi cosa sia necessaria, quindi tornando indietro e recuperando un altro.

Questo è in genere un po 'più semplice/più semplice in C++ perché è un po' più facile concordare alcune delle interfacce (ad esempio, sovraccaricare operator() per eseguire il codice per un'attività), ma a livello fondamentale puoi fare lo stesso cose in C (ad esempio, ogni struct task inserita nella coda conterrà un puntatore a una funzione per eseguire il lavoro per quell'attività).

Nel tuo caso, dal momento che stai usando C++, è probabilmente più facile usare un sovraccarico di operator() per fare il lavoro però. Il resto della struttura task conterrà tutti i dati necessari, ecc.

+0

Quindi, idealmente, la coda dovrebbe essere thread-safe e utilizzare un semaforo con un valore massimo del numero massimo di thread che ho intenzione di generare, giusto? Questa implementazione sembra un po 'sporca ... Non mi sembra giusto impostare i dati/contenitori "in bella vista", non incapsulato da una classe. Ecco perché ho chiesto di un'implementazione di pipe master-child_thread –

+0

L'overhead di avere una pipe parent_ child_PROCESS vale l'incapsulamento dei dati? –

+0

@ K-RAN: Quello che ho collegato (scorri verso il basso fino al "codice finale") * è * incapsulato in una classe. –

3

Dal POSIX standard:

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

(...) Il filo viene creato eseguendo start_routine con arg come unico argomento.

Quindi, è necessario creare un fascio di fili con questa funzione, e li hanno tutto eseguire una funzione che va qualcosa come

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

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

(Alla fine dell'input, spingere nSTOP_WORKING articoli alla coda dove n è il numero di fili.)

Intendiamoci, pthreads è un'API molto basso livello che offre pochissimo tipo di sicurezza (tutti i dati vengono passati come void p ointers). Se stai provando a parallelizzare le attività che richiedono un uso intensivo della CPU, potresti invece dare un'occhiata a OpenMP.

2

'non sembra fattibile poiché i thread terminano subito dopo il completamento del suo compito' che cosa ??

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

.. non restituire mai nulla, infatti, non tornare mai più.

+0

Non ci avevo mai pensato prima di questo post, né sapevo dei metodi di sonno pthread; la mia comprensione delle discussioni prima di questo era che sono cose uniche. –

-1

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

ho usato google un paio di mesi fa, si dovrebbe provare.

Modifica: sembra che tu voglia un gruppo invece. Sono stato in grado di crearne uno con qualche piccola modifica di quanto sopra, in modo che l'operatore non eseguisse il lavoro, ma si unisse ai thread.

+0

Hai qualche idea su come integrare questo threadpool nella libreria di eventi come libevent. Sembra avere il proprio loop infinito che aspetta l'attività per il thread. –

2

Potrebbe essere utile consultare the source code for libdispatch, che è la base per il Grand Central Dispatch di Apple e utilizza i pool di thread.

+1

Whoa, interessante. Grazie! –

1

Suggerirei di utilizzare Threaded Building Blocks da Intel per eseguire attività simili a work-queue/threadpool. Un esempio abbastanza artificioso con TBB 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; 
} 

utilizzati in seguito in questo modo:

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); 
}