2012-06-28 7 views
6

Con OpenMP 3.1, è possibile avere una clausola reduction con min:Trovare elemento minimo di matrice e il suo indice

double m; 
#pragma omp parallel for reduction(min:m) 
for (int i=0;i< n; i++){ 
    if (a[i]*2 < m) { 
    m = a[i] * 2; 
} 
return m; 

Supponiamo Ho anche bisogno del dell'indice dell'elemento minimo; c'è un modo per usare la clausola reduction per questo? Credo che l'alternativa è scrivere la riduzione manualmente usando nowait e critical.

risposta

5

Supponiamo di aver anche bisogno dell'indice dell'elemento minimo; c'è un modo per usare la clausola di riduzione per questo?

Purtroppo, no. l'elenco delle possibili riduzioni di OpenMP è molto ... piccolo. In particolare, le min e max sono le uniche funzioni "di livello superiore" e non sono personalizzabili. Affatto.

Devo ammettere che non mi piace l'approccio di OpenMP alle riduzioni, proprio perché non è estensibile al minimo, è progettato solo per lavorare su casi particolari. Certo, questi sono casi speciali interessanti ma è ancora fondamentalmente un approccio sbagliato.

Per tali operazioni, è necessario implementare personalmente la riduzione accumulando i risultati locali del thread in variabili locali del thread e combinandole alla fine.

Il modo più semplice per eseguire questa operazione (e in effetti abbastanza vicino a come OpenMP implementa riduzioni) consiste nell'avere un array con elementi per ogni thread e utilizzare omp_get_thread_num() per accedere a un elemento. Si noti tuttavia che questo porterà a un peggioramento delle prestazioni a causa della condivisione errata se gli elementi nell'array condividono una linea di cache. Per ovviare a questo problema, controlla l'array:

struct min_element_t { 
    double min_val; 
    size_t min_index; 
}; 

size_t const CACHE_LINE_SIZE = 1024; // for example. 
std::vector<min_element_t> mins(threadnum * CACHE_LINE_SIZE); 

#pragma omp parallel for 
for (int i = 0; i < n; ++i) { 
    size_t const index = omp_get_thread_num() * CACHE_LINE_SIZE; 
    // operate on mins[index] … 
} 
+0

Immagino che intendessi "omp_get_num_threads'? – user1071136

+0

@ user1071136 No, intendo 'omp_get_thread_num'. Vogliamo l'* indice *, non il numero totale. E per 'threadnum', questo è un segnaposto. Non puoi usare 'omp_get_num_threads' qui poiché non sei all'interno di una regione parallela. Invece, dovresti effettivamente passare 'numthread' come numero di thread nella successiva clausola parallela. –

+0

+1 per aver menzionato la condivisione errata. Tuttavia, le clausole di riduzione di OpenMP sono state progettate per l'efficienza e l'implementazione facile, non per estensibilità. –