2017-05-16 4 views
0

J'ai le code suivant:Pourquoi openMP se bloque-t-il sur une barrière dans un cycle de temps?

int working_threads=1; 
#pragma omp parallel 
    { 
     int my_num=omp_get_thread_num()+1; 
     int idle=false; 
     while(working_threads>0) { 
      if(my_num==1) 
       working_threads=0; 
#pragma omp barrier                              
     } 
    } 

Si je le lance, chaque maintenant et puis se bloque sur la barrière. Plus il y a de threads, plus il est probable que cela arrive. J'ai essayé de le déboguer avec printf et il semble que parfois tous les threads ne sont pas exécutés et donc la barrière les attend pour toujours. Cela arrive dans la première itération, le second n'est évidemment jamais exécuté.

Est-ce un morceau de code invalide? Si oui, comment puis-je le changer? J'ai besoin de courir une boucle while en parallèle. On ne sait pas combien de boucles seront exécutées avant, mais il est garanti que tous les threads auront le même nombre d'itérations.

+0

_ "... il est garanti que tous les threads auront le même nombre d'itérations" _ - est-ce une propriété intrinsèque de la boucle ou est-ce réalisé en utilisant une variable partagée comme dans le cas démontré? Si le premier, rend simplement la variable conditionnelle privée. –

+0

Ce dernier, il est fait en testant contre une variable partagée. C'est aussi la raison de l'état de la course. – knezi

Répondre

1

En dépit de votre tentative de synchronisation avec la barrière, vous avez une condition de course sur working_threads qui peut facilement conduire à quantité inégale d'itérations:

thread 0        | thread 1 
...         | ... 
while (working_threads > 0) [==true] | ... 
    if (my_num == 1) [==true]  | ... 
     working_threads = 0   | ... 
            | while (working_threads > 0) [==false] 
    [hangs waiting for barrier]  | [hangs trying to exit from parallel] 

Pour corriger votre code spécifique, vous devez également ajouter une barrière entre la vérification de l'état de l'état et working_threads = 0.

#pragma omp parallel 
    { 
     int my_num=omp_get_thread_num()+1; 
     int idle=false; 
     while(working_threads>0) { 
#pragma omp barrier  
      if(my_num==1) 
       working_threads=0; 
#pragma omp barrier                              
     } 
    } 

Notez que le code n'est pas exactement la solution la plus idiomatique ou élégante. Selon votre problème de travail partagé, il pourrait y avoir une meilleure approche. Aussi, vous devez vous assurer que worker_threads est écrit uniquement par un seul thread - ou utiliser des atomes lors de l'écriture.

+0

Merci, je ne suis pas sûr de savoir comment le rendre plus idiomatique. L'idée est que chaque thread obtient un intervalle. Cependant, on ne sait pas à l'avance combien de temps prend un intervalle particulier. Par conséquent, chaque intervalle est divisé en plus d'itérations qui sont calculées un par un dans le temps. S'il y a un thread IDLE, il obtient simplement une partie d'un intervalle de quelqu'un d'autre pour l'itération nex. – knezi

+1

@knezi, tu ne peux pas utiliser de tâches? Ceux-ci sont bien adaptés aux problèmes récursifs tels que le vôtre. –

+1

Il semble que vous pourriez avoir encore plus de conditions de course si vous essayez d'implémenter le vol de travail. Les tâches peuvent être une solution, mais je ne comprends pas suffisamment votre problème sous-jacent pour être plus précis. – Zulan