C parallèle OpenMP quickSort

Une fois de plus, je suis coincé lors de l'utilisation d'openMP en C++. Cette fois, je suis en train de mettre en œuvre un parallèle quicksort.

Code:

#include <iostream>
#include <vector>
#include <stack>
#include <utility>
#include <omp.h>
#include <stdio.h>
#define SWITCH_LIMIT 1000
using namespace std;
template <typename T>
void insertionSort(std::vector<T> &v, int q, int r)
{
int key, i;
for(int j = q + 1; j <= r; ++j)
{
key = v[j];
i = j - 1;
while( i >= q && v[i] > key )
{
v[i+1] = v[i];
--i;
}
v[i+1] = key;
}
}
stack<pair<int,int> > s;
template <typename T>
void qs(vector<T> &v, int q, int r)
{
T pivot;
int i = q - 1, j = r;
//switch to insertion sort for small data
if(r - q < SWITCH_LIMIT) 
{
insertionSort(v, q, r);
return;
}
pivot = v[r];
while(true)
{
while(v[++i] < pivot);
while(v[--j] > pivot);
if(i >= j) break;
std::swap(v[i], v[j]); 
}
std::swap(v[i], v[r]);
#pragma omp critical
{
s.push(make_pair(q, i - 1));
s.push(make_pair(i + 1, r));        
}
}
int main()
{
int n, x;
int numThreads = 4, numBusyThreads = 0;
bool *idle = new bool[numThreads];
for(int i = 0; i < numThreads; ++i)
idle[i] = true;
pair<int, int> p;
vector<int> v;
cin >> n;
for(int i = 0; i < n; ++i)
{
cin >> x;
v.push_back(x);
}
cout << v.size() << endl;
s.push(make_pair(0, v.size()));
#pragma omp parallel shared(s, v, idle, numThreads, numBusyThreads, p) 
{
bool done = false;
while(!done) 
{
int id = omp_get_thread_num();
#pragma omp critical
{
if(s.empty() == false && numBusyThreads < numThreads) 
{
++numBusyThreads;
//the current thread is not idle anymore
//it will get the interval [q, r] from stack
//and run qs on it
idle[id] = false;
p = s.top();                    
s.pop();
}
if(numBusyThreads == 0)
{
done = true;
}
}
if(idle[id] == false)
{
qs(v, p.first, p.second);
idle[id] = true;
#pragma omp critical 
--numBusyThreads;
}
}
}
return 0;
}

Algorithme:

À utiliser openMP pour une fonction récursive, j'ai utilisé une pile de garder une trace de la prochaine intervalles sur lesquels la qs de la fonction doit être exécutée. J'ai ajouter manuellement le 1er intervalle [0, la taille], puis laissez-les fils se rendre au travail lorsque l'intervalle est ajouté à la pile.

Le problème:

Le programme se termine trop tôt, de ne pas trier le tableau après la création de la 1ère série d'intervalles ([q, i - 1] [i+1, r] si vous regardez sur le code. Ma conjecture est que les threads qui obtiennent le travail, considère les variables locales de la fonction quicksort(qs dans le code) partagé par défaut, de sorte qu'ils désordre et de ne pas ajouter de l'intervalle dans la pile.

Comment je compile:

g++ -o qs qs.cc -Wall -fopenmp

Comment je cours:

./qs < in_100000 > out_100000

où in_100000 est un fichier contenant 100000 sur la 1ère ligne suivie par 100k entier sur la ligne suivante séparés par des espaces.

Je suis en utilisant gcc 4.5.2 sur linux

Merci pour votre aide,

Dan

La dernière fois je n'ai omp (ou même pthread) tri parallèle, il a été plus lente que la série + récursive. Sauf si vous êtes sûr que le serialness de la sorte est le goulot d'étranglement, vous êtes en train de faire l'optimisation prématurée.
Je suis sûr que la solution parallèle devrait mieux fonctionner. Cependant, je suis en train d'apprendre à utiliser openMP et je n'ai pas de connaissances approfondies sur ce qui se passe réellement dans les coulisses.
Sur une sorte de fusion de 1 000 000 d'éléments, le parallélisme avait trop haut dans le ciel. Et vous ne pouvez pas être sûr à 100%, sans un générateur de profils et de chiffres. Cela dit, ce n'est pas mauvais d'un exercice pour l'apprentissage de l'omp, ou pthreads. Pthreads va être un peu plus facile, car il est plus facile de faire récursive threads. Cela étant dit, vous devez utiliser un pool de threads et d'allouer des aides à la piscine. N'oubliez pas d'utiliser le verrouillage de la globals pour éviter des conditions de course, les blocages et autres ignominies.
Aussi, c'est une Bonne Pratique pour l'entourer d'en-tête C comprend avec extern "C" { ... }.
Eh bien, je veux savoir quel est le problème avec cette mise en œuvre le 1er.

OriginalL'auteur Dan Lincan | 2011-11-05