IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Java Discussion :

Programmation concurrente et BlockingQueues


Sujet :

Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 54
    Par défaut Programmation concurrente et BlockingQueues
    Bonjour,

    Je travaille actuellement sur une application multithreads, l'algorithme de déclenchement est, grosso-modo le suivant :
    . Le resultat du travail de chaque process est stocké dans une Map
    . Tous les process ont le meme comportement

    Comportement :
    --Si le process est autorisé à générer des process fils
    ---- Générer n fils suivant le meme comportement et leur donner un lien sur la Map
    ---- Tant que les n fils n'ont pas terminé
    ------ Attendre
    ---- Ecrire le resultat de traitement local dans la Map
    ---- Se terminer

    Le but est içi de faire collaborer plusieurs processus dans un travail réparti. Je bloque cependant sur la manière que va utiliser le process FILS pour informer son PERE qu'il vient de terminer son travail.

    J'ai essayé de remplacer la boucle d'attente par un wait() avec un moniteur sur l'objet this, mais je me suis trouvé confronté a un problème assez connu : les signaux se perdent...
    Exemple :

    P génere F1 et F2
    P attend (il doit rester 2 fils actifs)
    F1 fait son job
    F2 fait son job
    F1 envoie un notify
    F2 envoie un notify
    P capte un signal
    P attend (il doit rester 1 fils actif)
    ... Blocage

    Je suis en train d'explorer la piste des BlockingQueues pour faire transiter un message entre chaque fils et un pere , mais je me demande s'il n'existe pas une procédure plus simple.

    Merci d'avance pour le coup de pouce.

  2. #2
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Salut,


    Pour résoudre ce problème de notification perdu, il faut que tu gère une variable synchronisé qui compte le nombre de fils. Par exemple dans le père ta condition d'attente serais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    synchronized(this) {
        if (this.nbFilsActif > 0) {
            this.wait();
        }
    }
    nbFilsActif serait initialisé au lancement des fils, et décrémenté avant chaque notify :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    synchronized(this) {
        this.nbFilsActif --;
        this.notify();
    }


    Sinon l'utilisation des BlockingQueue n'est pas forcément la meilleure solution (a moins que tu doivent faire passer des données des threads fils vers le thread parent).

    a++

  3. #3
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 54
    Par défaut
    Citation Envoyé par adiGuba
    Salut,
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    synchronized(this) {
        this.nbFilsActif --;
        this.notify();
    }
    Le seul problème à ta solution est que la variable nbFilsActif d'un process référence le nombre de fils qu'il a généré, et non le nombre de fils que son père a généré.
    Je ne peux pas partager cette variable car je ne sais pas combien de fils vont devenir parent...

    L'utilisation d'une methode chez le pere conviendrait elle ?
    Le pere possede une methode :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    private synchronized void nbFilsMoinsMoins() { // synchronized or not ?
      synchronized(this) {
        nbFilsActif--;
        if(nbFilsActif==0) 
          notify();
      }
    }
    Le fils effectue un appel à cette méthode avant sa mort.

    Autre question : le fait de placer un moniteur sur l'objet this me garantie-t-il que tous les attributs de l'objets sont accédés de manière exclusive ?

  4. #4
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Junta
    L'utilisation d'une methode chez le pere conviendrait elle ?
    Oui je parlais bien d'exécuter ce code chez le père. Je me suis mal exprimé c'est vrai...

    Citation Envoyé par Junta
    Autre question : le fait de placer un moniteur sur l'objet this me garantie-t-il que tous les attributs de l'objets sont accédés de manière exclusive ?
    Non : le fait de placer un moniteur sur l'objet this te garantit seulement qu'aucun autre thread ne peut poser de moniteur sur cette référence. Si c'est le cas les autres threads seront mis en attente avant d'exécuter le code présent dans le bloc synchronized. Donc si des attributs doivent être accédés de manière exclusive, c'est à toi de t'assurer qu'il ne le sont que depuis l'intérieur de bloc synchronized...


    Enfin ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    public synchronized void method() {
        ...
    }
    Est équivalent à ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public void method() {
         synchronized(this) {
               ...
         }
    }
    Donc inutile de le doubler

    a++

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Juillet 2004
    Messages
    54
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juillet 2004
    Messages : 54
    Par défaut
    J'ai testé, et ça ne marche pas ...

    J'obtiens ceci :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Exception in thread "10891203" java.lang.IllegalMonitorStateException: current thread not owner
            at java.lang.Object.notifyAll(Native Method)
    Sur le bout de code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        public void deuil() {
            synchronized(nbFils) {
                nbFils--;
                if(nbFils==0)
                    nbFils.notifyAll();
            }
        }
    Sachant que
    - J'ai placé un moniteur sur l'objet nbFils pour etre sur qu'il n'y ait pas d'acces concurrent sur cette variable
    - nbFils est bien un objet java.lang.Integer et non un int
    - Cette exception est levée lorsqu'un fils tente d'appeler la méthode deuil() sur son père.

    => J'ai du oublier quelque chose, mais quoi ? Je ne peux pas changer le synchronized(nbFils) en synchronized(this) puisque ma variable pourra alors etre modifiée par deux Threads simultanément ...


    EDIT : Je viens de tenter la modification synchronized(this) en synchronized(nbFils), cela fonctionne. En fait puisque la variable nbFils n'est modifiée qu'à cet endroit précis du code, le résultat reste cohérent.

    EDIT² : Je veux quand meme bien savoir pourquoi est-ce que sur un objet Integer, le notify ne passe pas...

  6. #6
    Expert éminent
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par Junta
    EDIT : Je viens de tenter la modification synchronized(this) en synchronized(nbFils), cela fonctionne. En fait puisque la variable nbFils n'est modifiée qu'à cet endroit précis du code, le résultat reste cohérent.

    EDIT² : Je veux quand meme bien savoir pourquoi est-ce que sur un objet Integer, le notify ne passe pas...
    En fait il faut que la référence du synchronized soit la même que celle utilisé pour l'appel aux méthodes wait()/notify()/notifyAll()...

    Si cela semble être le cas dans ton code, ce n'est pas tout à fait vrai...

    En effet depuis Java 5.0 un système d'autoboxing/unboxing a été introduit afin de "simplifier" l'utilisation des types primitifs et de leurs équivalents Objets (plus de détails dans l'article de Lionel Roux : Présentation de Tiger - J2SE 5.0 : L'autoboxing).

    Par contre cela a des effets de bords assez indésirables...

    Par exemple le simple code suivant :
    Correspond en réalité au code suivant puisque Integer est immuable :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    nbFils = Integer.valueOf( nbFils.intValue()-1 );
    Et donc tu as une nouvelle référence pour nbFils... Tu peux vérifier cela avec le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
            Integer i = 0;
            System.out.println( System.identityHashCode(i) );
            i++;
            System.out.println( System.identityHashCode(i) );
    identityHashCode() renvoyant un code unique pour chaque objet différent (ce qui permet donc de distinguer les références).



    En général on utilise des références non-modifiable, comme this ou des attributs final :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    private final Object lock = new Object();
     
        public void deuil() {
            synchronized(lock) {
                nbFils--;
                if(nbFils==0)
                    lock.notifyAll();
            }
        }
    a++

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Quelle API pour la programmation concurrente ?
    Par 3DArchi dans le forum Threads & Processus
    Réponses: 16
    Dernier message: 19/12/2011, 08h51
  2. [Livre] Programmation concurrente en Java
    Par benwit dans le forum Général Java
    Réponses: 10
    Dernier message: 23/01/2011, 12h19
  3. Réponses: 18
    Dernier message: 29/07/2010, 23h57

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo