2013-06-17 17 views
6

Devo gestire il seguente scenerio: Ho 5 compiti ("A", "B", "C", "D", "E"), mi piacerebbe parallelizzarli ma rispetto alle loro dipendenze. Devono essere eseguiti in un tale ordine:Catena di compiti C++

A --> B --\ 
C ----------> E 
D --------/ 

Quindi, "E" viene eseguita quando tutti i precedenti sono finiti e "B" deve essere eseguita dopo A. E qui è la mia domanda. Esistono soluzioni pronte per l'uso (STL, Boost)? O dovrò implementarlo basandosi su std :: thread?

+0

Aspetta, l'ho visto da qualche parte prima? –

+7

Se [N3558] (http://open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3558.pdf) è accettato, penso che questo potrebbe essere fatto come 'auto flow = std :: when_all (std :: async (A) .then (B), std :: async (C), std :: async (D)). then (std :: async (E)); '. – Xeo

+0

@Xeo Molto bello! In realtà, puoi quasi fare lo stesso con Boost.Thread in Boost 1.54.0 (che è attualmente in beta), ma dovrai implementare il when_all yourself. Fornisce il .then() (è incompleto ma se non hai bisogno di cambiare executor dovrebbe funzionare). – Klaim

risposta

11

check out TBB's Flow Graph o PPL.

L'esempio nel collegamento TBB mostra approssimativamente ciò che è stato abbozzato. Hai già formulato il tuo problema come attività astratte. Non c'è bisogno di scendere al livello del filo all'inizio.

1

È possibile utilizzare std :: thread che non ho mai utilizzato ma sembra piuttosto semplice.

Ecco un esempio di un semplice programma trovato su cppreference.com:

#include <iostream> 
#include <thread> 
#include <chrono> 

void foo() 
{ 
    // simulate expensive operation 
    std::this_thread::sleep_for(std::chrono::seconds(1)); 
} 

void bar() 
{ 
    // simulate expensive operation 
    std::this_thread::sleep_for(std::chrono::seconds(1)); 
} 

int main() 
{ 
    std::cout << "starting first helper...\n"; 
    std::thread helper1(foo); 

    std::cout << "starting second helper...\n"; 
    std::thread helper2(bar); 

    std::cout << "waiting for helpers to finish...\n"; 
    helper1.join(); 
    helper2.join(); 

    std::cout << "done!\n"; 
} 

È possibile utilizzare la funzione join() per attendere un filo alla fine. Ad esempio, si crea un nuovo thread che eseguirà l'attività A. Quindi si attende che finisca prima di creare un nuovo thread che eseguirà l'attività B.

Si dovrebbe compilare con g ++ -std = C++ 0x - pthread main.cpp

In alternativa è possibile cercare MPI e OpenMP che possono fornire alcune possibilità che std :: thread non può.

2

Penso che si possa fare questo con la direttiva OpenMP section che si può fare con ICC, GCC e MSVC. La direttiva OpenMP task è probabilmente una scelta migliore e può essere eseguita con ICC e GCC ma non con alcuna versione di MSVC.

Il codice seguente utilizza OpenMP sections. Poiché E viene eseguito dopo che tutte le altre attività sono terminate, è possibile parallelizzarlo e quindi nel seguente codice E viene eseguito da tutti i thread dopo aver completato A, B, C, D. Se E sta iterando su un ciclo, puoi parallelizzare il ciclo in questo modo. Non sono sicuro che sia quello che vuoi ma è facile farlo girare in un thread come se lo volessi.

#include <stdio.h> 
#include <omp.h> 

void A() { printf("A\n"); } 
void B() { printf("B\n"); } 
void C() { printf("C\n"); } 
void D() { printf("D\n"); } 
void E() { 
    printf("E: %d\n", omp_get_thread_num()); 
    #pragma omp for 
    for(int i=0; i<10; i++) { 
    //do something as a function of i 
    } 
} 

void foo() { 
#pragma omp parallel // starts a new team 
{ 
    #pragma omp sections // divides the team into sections 
    { 
    { A(); B(); } 
    #pragma omp section 
    { C(); } 
    #pragma omp section 
    { D(); } 
    } 
    E(); 
} 
} 

int main() { 
    foo(); 
}