Forum |  HardWare.fr | News | Articles | PC | S'identifier | S'inscrire | Shop Recherche
565 connectés 

  FORUM HardWare.fr
  Programmation
  C++

  Probleme de synchronisation ecriture tubes / multi threads fork

 


 Mot :   Pseudo :  
 
Bas de page
Auteur Sujet :

Probleme de synchronisation ecriture tubes / multi threads fork

n°1381727
shar
Posté le 06-06-2006 à 03:36:32  profilanswer
 

Salutations,
 
J'ai un peu de mal à capter comment les tubes fonctionnent à cause des résultats aléatoires que je récupère... Je vous explique.
 
J'ai pour mission de récupérer la liste des fichiers d'un sous arbre à partir d'un point donné du disque.
 
Exemple : ./monprog repdepart
 
Lors du parcours de repdepart, le programme va, s'il tombe sur un repertoire à l'interieur de repdepart, lancer un processus fils avec l'appel fork();.
 
Les processus communiquent entre eux la liste des fichiers trouvés via UN tube.
 
Donc, le tube est crée par le programme principal. Premier fork() : si je suis le fils, je ferme le tube en lecture et je lance l'algoryhtme sur (repdepart,tube).
Si je suis le pere, je ferme le tube en ecriture et j'attends par un while (read ...) des informations de mon fiston.
 
Maintenant, si le fils, lorsqu'il parcoure la liste des fichiers, trouve un repertoire, il crée un fils avec (repdepart/reptrouvé,tube);
 
Ainsi de suite.
 
 
Le probleme est le suivant :
Considérons le cas où tout les fils ont écris dans le tube, puis se terminent un à un, sans que le processus pere principal n'ait eu le temps d'executer un read(pipe). (habituellement il a le temps d'en faire juste un dans mon programme, des fois deux).
Le pere lorsqu'il va prendre la main, va executer un read(tube...) qui va lui retourner 0 ! Et ce malgré le fait qu'il y ait des choses à lire dans le tube !
Et pourquoi? Simplement parceque le tube a été fermé en écriture par tout les fils, le read considère qu'il n'ya plus rien à lire et retourne 0.
 
Donc il me faudrait un moyen de faire en sorte à forcer le read à lire TOUT le contenu du tube, qu'il y ai des processus ecrivains ou non.
Ou alors : Forcer la fermeture du tube en ecriture du premier fils (dans l'ordre des choses, les fils creent des fils etc mais tout se termine dans le sens inverse, les parents attendant que les enfants finissent) uniquement quand le processus pere principal aura fini de lire tout le contenu du tube!
 
Des idées? Je suis bloqué depuis 2 jours la dessus ><

mood
Publicité
Posté le 06-06-2006 à 03:36:32  profilanswer
 

n°1381763
nargy
Posté le 06-06-2006 à 09:07:07  profilanswer
 

> l'algoryhtme
- l'algorihtme
 
> Le probleme est le suivant :
- je dirai que le problème est que tu va vite exploser le nombre de processus de ton système... Enfin, je suppose que c'est un exercice.
 
Tu as oublié de préciser ce qu'il se passe quand un fils reçoit une info d'un autre fils. Y a t-il plusieurs tubes de créés, ou est-ce-que le même tube est utilisé par tous les fils? Tu va aussi exploser le nombre de fichiers ouverts par le système.
 
En fait, la condition d'arrêt de lecture du père, devrait être à la terminaison de tous les fils. De même, chaque fils attends que tous ses fils s'arrêtent avant de s'arrêter. Voir les fonctions wait() et waitpid().

n°1381925
shar
Posté le 06-06-2006 à 11:43:03  profilanswer
 

Alors pour le nombre de processus, oui j'ai ai bien pensé mais bon comme c'est un exercice on nous en demande pas trop.
A la limite on donne une variable nombre max fils par fils. Disons 5 fils max par fils, après il dois wait l'un de ses fils.
 
Alors pour le tube, il n'y a qu'un seul tube.
Le processus main :
tube=pipe()
pid=fork
if (pid==0)
{ close(tube[0]). Appel de la fonction qui va s'occuper de parcourir le rep donné en parametre, et lancer des fils sur la meme fonction à chaque sous rep trouvé.
return 1;
} else {
close(tube[1]);
while (read(tube[0],buffer,sizeof(buffer))
{
on traite les resultats
}
}
 
 

Citation :


En fait, la condition d'arrêt de lecture du père, devrait être à la terminaison de tous les fils.


 
Et c'est déjà le cas ! Le read retournera 0 lorsequ'il n'y aura plus personne pour ecrire dans le tube.
Et c'est justement le probleme.
 
Si les processus fils ecrivent, que le main lis, puis les fils se terminent, tout est OK le main a tout recu.
Si le processus main a la main moins souvent que les fils, les fils ecrivent mais le main n'a pas encore eu le temps de tout lire lorsque ses fils se terminent : le read renvoie 0 car il n'y a plus d'ecrivain (ce qui est vrai) mais il y a toujorus des choses à lire dans le tube!

n°1381964
franceso
Posté le 06-06-2006 à 12:16:30  profilanswer
 

C'est pas vraiment la question posée, mais j'ai quand même un doute sur ce type de fonctionnement : s'il n'y a qu'un seul tuyau et plusieurs fils écrivains (répartis sur plusieurs générations) qu'est-ce qui te garantit que les différents messages écrits par les fils ne se mélangent pas ?
 
Ne devrais tu pas 1) faire plusieurs tuyaux, ou 2) coordonner tes écritures (par exemple avec des signaux) ?
 
 
Pour ton problème de lecture dans le tuyau, je ne comprends pas d'où ça peut venir : normalement, si le fils fait une fermeture propre du tuyau avant de se terminer, les données ne devraient pas disparaître dans le vide intersidéral. Es-tu sûr que tous les fils se terminent proprement et ferment correctement leur tuyau ?


Message édité par franceso le 06-06-2006 à 12:16:50

---------------
TriScale innov
n°1381966
nargy
Posté le 06-06-2006 à 12:17:12  profilanswer
 

Citation :


En fait, la condition d'arrêt de lecture du père, devrait être à la terminaison de tous les fils.


Je re-confirme, tu ne m'a pas compris. Je parle bien de terminaison de fils, et non de fermeture de tube. D'ailleurs je ne suis même pas sûr qu'il soit réellement important de fermer le tube.
 
Pour vérifier si un processus fils se termine, utilise l'une des fonctions suivantes:

  • wait()
  • waitpid()

Tu trouvera le manuel de ces fonctions avec la commande Unix:
man 2 waitpid
...ou sur le net et tapant "man waitpid" avec les guillemets dans un moteur de recherche.

n°1381971
nargy
Posté le 06-06-2006 à 12:23:32  profilanswer
 

Pour répondre aux inquiétudes de francesco, oui, il y a un risque que les sorties des fils se mélangent.
 
Mais, le risque est minime si on fait un printf() car d'une part le chemin absolu d'un fichier est limité à 1024 octets, et d'autre part le buffer de printf() est bien souvent plus grand (4Ko).
 
Pour être cependant sûr que le code fonctionne sur des systèmes exotiques, il faut bien entendu utiliser une approche différente. Étant donné que créer plein de tubes peu poser problème, au niveau des ressources requises, et vaut mieux utiliser un <<cadenas>> sur le tube.
 
Pour celà, voir la fonction <<lockf>>, dans la section 3 du manuel Unix: man 3 lockf

n°1381989
shar
Posté le 06-06-2006 à 12:58:35  profilanswer
 

Je fait bien des wait(NULL)
 
Je vous inscris mon code, ce sera plus simple :
 

Code :
  1. int parcours(char * repertoire, int * tube)
  2. {
  3. cout<<"("<<getpid()<<" )" << "Fonction parcours sur : " << repertoire << endl;
  4. char cheminfich [1024];
  5. char liste[2048];
  6. close(tube[0]);
  7. struct dirent *lecture;
  8. DIR *rep;
  9. pid_t pid;
  10. rep = opendir(repertoire);
  11. char  temp[20];
  12. struct stat st;
  13. int childs=0;
  14.    if (rep) {
  15. while (lecture = readdir(rep))
  16. {
  17.  if ( (strcmp(lecture->d_name,".." )!=0 ) && (strcmp(lecture->d_name,"." )!=0) )
  18.  {
  19.   strcpy(cheminfich,repertoire);
  20.   strcat(cheminfich,"/" );
  21.   strcat(cheminfich,lecture->d_name);
  22.   lstat(cheminfich ,&st);
  23.   if ( ! S_ISDIR(st.st_mode) && ( st.st_mode & S_IFLNK ) != S_IFLNK )
  24.   {
  25.    strcat(liste,cheminfich);
  26.    sprintf(temp, "|%d", st.st_size);
  27.       strcat(liste,temp);
  28.    sprintf(temp, "|%d", st.st_ino);
  29.       strcat(liste,temp);
  30.    strcat(liste,"|" );
  31.   } else if (S_ISDIR(st.st_mode) && ( st.st_mode & S_IFLNK ) != S_IFLNK )
  32.   {
  33.    childs++;
  34.    pid=fork();
  35.    if (pid==0) {
  36.     return parcours(cheminfich,tube);
  37.    }
  38.   }
  39.  }
  40. }
  41. if (strlen(liste)>5) {
  42.  cout <<"("<<getpid()<<" )"<< "Ecriture dans le tube : " << liste << endl;
  43.  write(tube[1],liste,strlen(liste)+1);
  44.  }
  45.  closedir(rep);
  46.   }
  47. for (int i=0;i<childs;i++) { pid=wait(NULL); cout<<"("<<getpid()<<" ) A attendu une fois le fils : "<<pid<<endl; }
  48. close(tube[1]);
  49. cout<<"("<<getpid()<<" ) Je suis mort"<<endl;
  50. return 1;
  51. }
  52. int main (int argc, char * argv[])
  53. {
  54. Liste L;
  55. int tube[2];
  56. char chemin[512];
  57. char buffer[2048];
  58. int taille;
  59. int inode;
  60. pid_t pid;
  61. char * strsplit;
  62. if (argc!=2)
  63. {
  64.  cout<<"("<<getpid()<<" )"<<"Spécifiez un et un seul repertoire à analyser."<<endl;
  65.  exit(-1);
  66. }
  67. if (pipe(tube)<0)
  68. {
  69.  cout<<"("<<getpid()<<" )"<<"Impossible d'ouvrir un tube de communication"<<endl;
  70.  exit(-1);
  71. }
  72. pid=fork();
  73. if (pid==0)
  74. { parcours(argv[1],tube); return 1;}
  75. else {
  76.   close(tube[1]);
  77.  while (read(tube[0],buffer, sizeof(buffer)))
  78.   {
  79.    cout<<"("<<getpid()<<" )" << "Lu dans le tube : " << buffer << endl;
  80.    strsplit=strtok(buffer,"|" );
  81.    while (strsplit != NULL)
  82.    {
  83.     strcpy(chemin,strsplit);
  84.     strsplit=strtok(NULL,"|" );
  85.     taille=atoi(strsplit);
  86.     strsplit=strtok(NULL,"|" );
  87.     inode=atoi(strsplit);
  88.     L.ajoutTrieCroissant(chemin, taille, inode);
  89.     cout<<"("<<getpid()<<" )" << "Ajouté dans la liste : " << chemin << ":" << taille << ":" << inode << endl;
  90.     strsplit=strtok(NULL,"|" );
  91.    }
  92.   }
  93.  close(tube[0]);
  94.  cout <<"("<<getpid()<<" )"<< "Affichage de la liste des fichiers : " << endl;
  95.  L.affiche(cout);
  96. }
  97. wait(NULL);
  98. //suite qui n'a rien à voir...


Aller à :
Ajouter une réponse
  FORUM HardWare.fr
  Programmation
  C++

  Probleme de synchronisation ecriture tubes / multi threads fork

 

Sujets relatifs
Problème de compilation Inno SetupProblème de création de vignettes
Problème avec fscanf[c] Problème producteur-consommateur
probleme avec mon serpentProblème EasyPHP $_GET[param] sans guillemets (urgent svp)
[Résolu] Problème MySQL 1&1 : plus de protection de chaine !Problème excel... [RESOLU]
Gros problème de liens dans mon site..Probleme sur DataGridView sous VB DotNet
Plus de sujets relatifs à : Probleme de synchronisation ecriture tubes / multi threads fork


Copyright © 1997-2022 Hardware.fr SARL (Signaler un contenu illicite / Données personnelles) / Groupe LDLC / Shop HFR