Forum Programmation.c++ pthread : mutex, bien s'en servir

Posté par  . Licence CC By‑SA.
Étiquettes :
0
14
juin
2013

Salut,
Je suis en train de jeter un œil sur pthread (oui je sais C++11 arrive c'est plus la peine)
Mais le bon usage des mutex n'est pas clair pour moi

  • pthread_mutex_lock(&monmutex) : Si je comprend bien, lorsque plusieurs threads vérouillent le mutex, les autres se mettent en attente jusqu'à c que le mutex soit libéré ? 

  • pthread_cond_wait(signal,mutex) Va créer une sorte de slot qui attend un signal et va simplement attendre le signal, mais à quoi sert le mutex ? Est-ce que je dois faire référence au mutex avant d’appeler ma fonction ?

  • Est-ce que je peux locker un stream avec un mutex ? i.e. contrôler l'écriture sur cout ?

Voilà un bout de code, qui se contente d'afficher le contenu d'un vecteur d'entier, ça tourne, je soupçonne qu'il reste un heisenbug à l'intérieur, mais surtout j'ai mis mes lock un peu au hasard et j'aimerais faire ça proprement,
Le but du code est simple, j'ai un thread mère qui itére le vecteur et lance des threads filles qui ici se contente d'afficher le contenu du vecteur, sachant que je veux un nombre donnés de threads filles.

//Nthread, mutex_* cond_* sont des globales, c'est moche, mais pour un test c'est rapide 

    void* Mythread2(void* data) {
      //Ici par intéret pédago, on se contente d'afficher un entier, mais la tache pourrait être plus complexes 
      pthread_mutex_lock(&mutex_outlock);
      //Est-ce que ça locke cout ? apparement non 
      cout << ">> >> "<< *(reinterpret_cast<int*>(data)) << endl;
      pthread_mutex_unlock(&mutex_outlock);
      pthread_mutex_lock(&mutex_launchnew);
      //Le thread est presque finit on décrémente le compteur de thread
      Nthread--;
      pthread_cond_signal (&cond_launch);
      pthread_mutex_unlock(&mutex_launchnew);
    }

    void* MotherThread(void* data) {
      //L'idée c'est d'avoir un thread qui s'assure qu'on utilise pas plus de threads que ce que l'on veut 
      const int MaxThread=4;
      //C'est pas très C++ mais apparemement c'est ce que veut pthread
      vector<int>* params=reinterpret_cast<vector<int>* >(data);
      vector<int>::iterator iter=params->begin();
      while (Nthread<MaxThread) {
        if (iter==params->end()) break;
        pthread_t thread;
        int* pval=NULL;
        pval=&(*iter);
        pthread_create(&thread, NULL,Mythread2, reinterpret_cast<void*>(pval));
        ++Nthread;
        ++iter;
      }
      while (iter!=params->end()) {
      //Ici je veux locker mon compteur de threads pour garder un nombre
      //constants de threads qui tournent
      pthread_mutex_lock(&mutex_launchnew); 
      pthread_t thread;
      //On va attendre qu'un thread soit finit pour en lancer un autre
      // C'est surement plus éléguant qu'un while(true)
      pthread_cond_wait(&cond_launch,&mutex_launchnew);
      while (Nthread<MaxThread) {
        int* pval=NULL;
        pval=&(*iter);
        pthread_create(&thread, NULL,Mythread2, reinterpret_cast<void*>(pval));
        Nthread++;
        ++iter;
        cout << "Starting new thread, at the moment there is " << Nthread << "running" << endl;
        }
      //On a lancé le thread on peut dévérouiller
      pthread_mutex_unlock(&mutex_launchnew);
      }

    }

En relisant le code, j'ai 2-3 doutes qui viennent,

  • Si un thread se finit alors que mon autre thread tourne déjà, que devient le slot qui attend la fin d'un thread pour en lancer un ?  J'imagine que le while est une solution au problème cas si je manque la fin d'un thread je serais avertit lorsque le prochain se termine.
  • Il y a pas un moyen plus éléments de compter le nombre de thread en cours ? car incrémenter/décrementer un compteur c'est moche

merci pour vos conseils/commentaires

  • # E_NOVALID

    Posté par  . Évalué à 2.

    La réponse à tes questions est tout simplement que ta manière de faire n'est pas valide.

    man: pthread_join

    • [^] # Re: E_NOVALID

      Posté par  . Évalué à 1.

      J'ai bien pensé à pthread_join, mais d'après ce que j'ai compris
      pthread_join stoppe le programme jusqu'à ce que le thread joigne, donc si j'ai 4 Threads (numéroté de 1 à 4), pendant que j'attends que le thread 1 soit finit, les threads 3 et 4 vont se finir et je ne détecterais leurs fin que lorsque le thread 1 sera finit,
      il y a bien pthread_tryjoin_np, mais ça me force de toute façon soit à avoir une boucle qui tourne en attendant qu'il se passe quelques chose, soit à intercepter un message,
      Questions bonus, pthread_tryjoin_np c'est non portable à quel point ? Ça marche chez moi, je suppose aussi sous win win, et quid du reste ?
      Bref cette version est elle vraiment meilleure ? c'est vrai qu'elle est plus courte pour le même résultat et se passe de mutex et autres globales, mais j'ai l'impression que je vais devoir les rajouter

      while (iter!=params->end()) {
        int* pval=NULL;
        pval=&(*iter);
        while (threads.size()<MaxThread && iter!=params->end())  {
          int* pval=NULL;
          pval=&(*iter);
          pthread_t Thethread;
          threads.push_back(Thethread);
          pthread_create(&threads.back(), NULL,Mythread2, reinterpret_cast<void*>(pval));
          ++iter;
          }
        for(vector<pthread_t>::iterator thiter=threads.begin();thiter!=threads.end();++thiter) {
          if (pthread_tryjoin_np(*thiter,NULL)==0) {
        threads.erase(thiter);
        }
        }
      
      

      }

Suivre le flux des commentaires

Note : les commentaires appartiennent à celles et ceux qui les ont postés. Nous n’en sommes pas responsables.