# [C] Différences lib pthread Mac et linux?



## Gui13 (18 Mars 2007)

Bonjour à tous, 

J'ai fini de coder un programme qui calcule une multiplication de matrices en parallele en appelant des threads (c'est un programme pédagogique hein, c'est pas pour du calcul scientifique, c'est juste pour maitriser les threads et les fork).

Bref, passons aux choses intéressantes: mon code C compile bien que ce soit sous linux ou sous Mac.
Par contre, l'excecution plante sous Mac (mon macbook core duo) alors que sous linux elle fonctionne! Et ce que la machine soit Mono ou multiprocesseur (4 cores xeon, ca fonctionne).

Alors je me demande si c'est pas la librairie pthread qui est différente sous Mac que sous linux?

Si je fais un gcc -v sous une des machines linux, j'ai ca: 

Modèle de thread: posix
version gcc 3.3.5 (Debian 1:3.3.5-13) 

(machine: athlon 1Ghz)

Sous mac j'ai ca:

Thread model: posix
gcc version 4.0.1 (Apple Computer, Inc. build 5250)

J'ai l'impression que c'est au niveau de la fonction pthread_join que ca chie, vous en pensez quoi?

Si vous avez besoin, je peux filer le code (qui je le rapelle, est totalement fonctionnel sous linux).

Merci en tout cas


----------



## ntx (18 Mars 2007)

pthread doit fonctionner sur Mac OSX. Dans le man, on peut lire ceci:


> STANDARDS
> The functions in libc with the pthread_ prefix and not _np suffix or
> pthread_rwlock prefix conform to ISO/IEC 9945-1:1996 (``POSIX.1'').
> 
> ...


Est-ce bon pour ton programme ?


----------



## Gui13 (19 Mars 2007)

ntx a dit:


> pthread doit fonctionner sur Mac OSX. Dans le man, on peut lire ceci:
> 
> Est-ce bon pour ton programme ?



Non toujours pas, et je ne comprends pas ou est la faute...

Voilà le code qui flanche: 


```
#include <pthread.h>
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>

#include "types.h"
#include "pmat.h"
#include "mat.h"
#include "tab.h"


uint * choix;                  /* tableau 'choix' dans l'algo du boulanger                        */
uint * numero;                 /* tableau 'numero' dans l'algo du boulanger                       */
int * term;                    /* tableau indiquant la terminaison des taches pour le rendez-vous */
pthread_t * threads = NULL;    /* tableau stockant les identifiants de chaque thread              */


void * fun( void * arg )
{
  uint i; 
  int z; /* l'indice de ma boucle */
  thread_arg a; 
  
  /* On convertit l'argument 'arg' pour recuperer le bon type */
  a = (thread_arg) arg;
  
  i = a->k; /* i est egal à k ici, ca simplifie le reste */
  printf("Je suis le thread numero %d, je vais faire une petite demande de calcul\n",i);
  /* Algorithme du boulanger, straight from the paper */
  choix[i] = 1; /* on signale qu'on demande un accès */
  numero[i] = 1 + max( numero , a->m1->l ); /* on prend le numéro suivant dans le tableau des numéros */
  choix[i] = 0; /* on a fini de demander un numero */
  for (z = 0; z < a->m1->l; z++)
    {
      while (choix[z]){ /* tant que quelqun est encore dans la liste de demande, on lui laisse le passage */
      }
      while(numero[z] && ((numero[z]<numero[i]) || ((numero[z] == numero[i]) && (z < i))) ){
      }
      /* on a fini d'attendre, c'est à nous, ouf! */
    }
  

  
  printf("Tache %d :Je calcule r[%d][%d]= %f + (%f)*(%f)....\n",i,a->i,a->j,a->r->data[a->i][a->j],a->m1->data[a->i][a->k],a->m2->data[a->k][a->j]);
  
  /* Debut de la section critique */
  a->r->data[a->i][a->j] += (a->m1->data[a->i][a->k])*(a->m2->data[a->k][a->j]);
  
  /* Fin de la section critique */
  printf("Tache %d : Fini!\n",i);
 
  numero[i] = 0; /* on rend notre ticket */
  /* Fin de la sortie de la section critique */

  return NULL; 
}


/* 
   Fonction qui lance les threads pour effectuer le calcul parallele. 
*/
mat mat_pmul( mat m1, mat m2 )
{

  thread_arg targs = NULL; /* tableau des arguments des threads */
  mat r = NULL; 
  uint i, j, k = 0;
  
  /* On connait la taille de la matrice resultat, on alloue */
  r = mat_new_zeros( m1->h, m2->l );
  
  /* On alloue la place pour les tableaux */
  threads = malloc( m1->l*sizeof( *threads ) );
  targs   = malloc( m1->l*sizeof(  *targs  ) );
  choix   = malloc( m1->l*sizeof(  *choix  ) );
  numero  = malloc( m1->l*sizeof( *numero  ) );
  term    = malloc( m1->l*sizeof( *term    ) );
  
  /* Ce qui ne changera pas d'une execution sur l'autre */
  for ( k= 0; k< m1->l; k++ )
    {
      term[k] = 0;
      targs[k].m1 = m1;
      targs[k].m2 = m2;
      targs[k].r  =  r;
    }

  /* on double-boucle sur la matrice entiere */
  for ( i= 0; i< r->h; i++ )
    for ( j= 0; j< r->l; j++ )
      {
	/* pour chaque appel de thread a l'iteration (i,j)... */
	for ( k= 0; k< m1->l; k++ )
	  {
	    term[k] = 0;
	    choix[k] = 0;
	    numero[k] = 0;
	    threads[k] = 0;
	    targs[k].i = i;
	    targs[k].j = j;
	  }
	
	/* on lance les threads */
	for ( k= 0; k< m1->l; k++ )
	  {
	    targs[k].k = k; /* il ne manquait plus que de savoir quel calcul faire */

	    pthread_create(&threads[k] , NULL , fun , &targs[k]);
	    
	  }
	
	/* Avant de passer au coefficient suivant, on verifie
	   que tous les threads ont termine...
	*/
	printf("Jointure des threads \n");
	for ( k= 0; k< m1->l; k++ )
	  {
	    if (pthread_join(threads[k],NULL) == 0){
	      threads[k] = 0;
	      printf("Thread %d joint\n",k);
	    }
	    else{
	      printf("Erreur : thread %d non fini\n",k);
	    }
	  }
	  printf("Fin de jointure des threads, on passe au coef suivant...\n");
	/* ... */
	
      }
  
  /* on fait le menage... */
  free( targs );
  free( threads );
  free( numero );
  free( choix );
  
  return r; 
}
```

En gros on lance N threads par coeficient à calculer, un par a(i,k)*b(k,j), et on utilise l'algorithme du boulanger pour que les threads ne viennent pas écrire sur un résultat alors qu'un autre l'ecrit aussi.

Je pense que c'est à la jointure des threads (ligne 117) que le programme plante, car dans mon terminal j'obtiens ca:


```
Appuyer sur une touche!


Je suis le thread numero 0, je vais faire une petite demande de calcul
Jointure des threads 
Je suis le thread numero 1, je vais faire une petite demande de calcul
Je suis le thread numero 2, je vais faire une petite demande de calcul
Tache 0 :Je calcule r[0][0]= 0.000000 + (0.003217)*(0.526757)....
Tache 0 : Fini!
Thread 0 joint
^C
```
 (le ^C montre que je control+C pour arreter le programme qui répond pas...)

A moins que ce soit mon algo du boulanger, mais alors dans ce cas pourquoi il fonctionne sous Linux?


----------



## ntx (19 Mars 2007)

Gui13 a dit:


> A moins que ce soit mon algo du boulanger, mais alors dans ce cas pourquoi il fonctionne sous Linux?


C'est possible, la gestion de la mémoire n'est pas la même.
Ajoute de traces partout, passe par le debugueur. Tu finiras bien par trouver où ça coince.

PS : il manque un free(term).


----------

