2015-11-12 9 views
6

Sto cercando di imparare le basi del calcolo parallelo, ma sto riscontrando un problema sul mio computer. Dai un'occhiata al mio codice qui sotto. Fondamentalmente, voglio stampare la riga "Hello World!" per ogni core del mio computer. Il mio computer ha quattro core, quindi dovrebbe stampare quella linea quattro volte. Se dovessi usare la linea "cout" commentata invece della linea "printf", l'output sarebbe tutto confuso. Questo perché il comando \ n 'escape viene eseguito separatamente da "Hello World!", Quindi il nuovo output di riga si verificherebbe in modo casuale. La linea 'printf' è una soluzione a questo problema, perché la linea viene eseguita tutto in una volta (non divisa in parti come la linea 'cout'). Tuttavia, quando uso 'printf', il mio output è ancora tutto confuso come se usassi 'cout'. Non ho idea del motivo per cui lo fa. Ho provato lo stesso identico codice su un altro computer, e funziona perfettamente. È solo il mio computer che continua a confondere l'output con 'printf'. Ho mandato un'email al mio professore di CS e non ha idea del perché lo stia facendo sul mio computer. So di aver installato OpenMP sul mio computer correttamente. Qualcuno con esperienza di calcolo in parallelo sa perché questo sta rovinando il mio computer?Calcolo parallelo - output confuso?

#include <omp.h> 
#include <stdio.h> 
#include <iostream> 
#include <stdlib.h> 
using namespace std; 

int main() 
{ 
    #pragma omp parallel 
    { 
     printf("Hello World!\n"); 
     //cout << "Hello World!\n" << endl; 
    } 
    return 0; 
} 

Per mostrare di cosa sto parlando, qui è l'uscita dal momento in cui ho eseguito il codice di cui sopra sul mio computer:

Ciao Wo

Ciao Mondo!

rld!

Ciao mondo!

+0

Ho appena provato con 'cout' e ha funzionato in modo impeccabile: http://ideone.com/dPPQeO –

+0

La parte' endl' potrebbe essere la fonte di problemi, poiché svuota il buffer di output. –

+4

Questo è praticamente ciò che dovresti aspettarti quando esegui le cose in parallelo. Non c'è nulla che impedisca l'esecuzione di printf di Core 1 nel mezzo di Core 2. Questo è il motivo per cui la programmazione parallela è difficile. – immibis

risposta

6

Scusa, il tuo professore ha sbagliato. È necessario sfruttare l'esclusione reciproca o alcuni altri ostacoli al fine di garantire l'uso ininterrotto di una risorsa condivisa (che in questo caso è il file di output STDOUT).

L'output misto è un potenziale comportamento previsto a prescindere da printf o std::cout::operator<<(). Le differenze di comportamento che vedi sono sottili differenze nella durata di esecuzione di ciascuna, a causa del loro diverso design. Dovresti aspettarti questo comportamento in entrambi i casi.

Non capisco perché funzionerebbe per tutti gli altri.

Non lo è. Sii un eroe della tua classe e spiega come funziona e come risolverlo. Di 'loro che manda il loro amore. :)

4

Come già spiegato, l'ipotesi che printf() sia atomica e non mancherà la tua uscita mentre std::cout::operator<<() non è e farà pasticci se fondamentalmente sbagliato.

Tuttavia, c'è ancora una (piccola) parte di "verità" in questo, ma a un livello diverso.Lasciate che vi faccia un esempio:

Se provo un OpenMP "Ciao mondo" in stile C, che potrebbe dare a questo:

printf("Hello from thread %d of %d\n", 
     omp_get_thread_num(), 
     omp_get_num_threads()); 

Lo stesso C++ - stile potrebbe essere la seguente:

std::cout << "Hello from thread " << omp_get_thread_num() 
      << " of " << omp_get_num_threads() 
      << std::endl; 

e la differenza fondamentale tra i due è che per printf(), ho solo chiamo il metodo di stampa una volta, con una stringa di output completamente preparati, mentre il C++ - stile uno chiamerà std::cout::operator<<() 5 volte, con soli pezzi di linee che può o non può essere inviato a l'output standard. Internamente, può succedere di tutto e non cercherò di impegnarmi in alcun tipo di comportamento. Ma almeno usando lo printf() qui, aumento le mie possibilità di un output pulito, anche se non posso garantirlo.

Ecco un esempio completo:

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

int main() { 
    #pragma omp parallel 
    printf("Hello from thread %d of %d with printf()\n", 
      omp_get_thread_num(), 
      omp_get_num_threads()); 

    printf("*** outside of parallel region ***\n"); 

    #pragma omp parallel 
    std::cout << "Hello from thread " << omp_get_thread_num() 
       << " of " << omp_get_num_threads() 
       << " with std::cout" 
       << std::endl; 
    return 0; 
} 

che sul mio portatile Linux mi dà (GCC 5.2):

~/tmp$ g++ -fopenmp stdout.cc 
~/tmp$ ./a.out 
Hello from thread 3 of 4 with printf() 
Hello from thread 0 of 4 with printf() 
Hello from thread 2 of 4 with printf() 
Hello from thread 1 of 4 with printf() 
*** outside of parallel region *** 
Hello from thread Hello from thread Hello from thread Hello from thread 1 of 4 with std::cout23 of 4 with std::cout 
of 4 with std::cout 
0 of 4 with std::cout 

~/tmp$ 

Se si guarda attentamente, si può vedere che nessuna delle singole chiamate a std::cout::operator<<() è diviso, ma ogni nuova chiamata è un'opportunità per i vari thread di rincontrarsi l'un l'altro, e per ottenere l'output alterato.

Quindi, ancora una volta, dire che printf() è atomico e non rovinerà le cose è sbagliato, ma semplicemente, per una stringa di output complessa, è meno probabile che venga storpiato rispetto a std::cout.