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

API standards et tierces Java Discussion :

Synchronized mal compris ou HS?


Sujet :

API standards et tierces Java

  1. #1
    Membre confirmé Avatar de flotho
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Novembre 2006
    Messages
    156
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Novembre 2006
    Messages : 156
    Par défaut Synchronized mal compris ou HS?
    Bonjour à tous,

    Voici le contexte :
    J'ai un dev en cours qui nécessite une captation d'image par 2 webcams. Celles ci ne peuvent être lues simultanément donc j'ai un accès concurrentiel.
    Je prends le temps de lire les FAQ et Tuto sur les thread et la synchronisation.
    Je développe et cela ne fonctionne pas comme je l'imagine. je me pose des questions, cherche, discute avec le dev de l'API que j'utilise (v4l4j) il me dit que ma synchro n'est pas correcte. Je vérifie, re regarde, relis...
    Et je finis par tester tout simplement le tuto synchro et là PAF: En ajoutant la clause synchronized cela ne fonctionne pas comme proposé dans le tuto.

    MA QUESTION :
    Est ce normal que ce dernier test échoue ou bien y a t il quelque chose de spécial à activer dans la JVM pour que cela fonctionne?

    Un grand merci d'avance à vous car je dois dire que plus basique on peut pas faire et que j'en perds mes cheveux.

  2. #2
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Sans code, c'est compliqué de te suivre... Peux-tu illustrer le problème par un petit programme ?
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  3. #3
    Membre confirmé Avatar de flotho
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Novembre 2006
    Messages
    156
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Novembre 2006
    Messages : 156
    Par défaut
    Bien sûr,

    j'ai simplement utilisé cela :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    /*
    /**
     * @author Valère VIANDIER
     *
     */
    public class VaseComuniquant {
        private static final int QUANTITE_INITIALE = 200;
        private static final int NB_THREAD_MAX = 2;
     
        private static int iteration = 0;
     
        private int[] vase = {QUANTITE_INITIALE / 2,QUANTITE_INITIALE / 2};
     
        public VaseComuniquant() {
            for( int i = 0; i < NB_THREAD_MAX; i++)
                new ThreadTransfert().start();
        }
        public static void main(String[] args) {
            new VaseComuniquant();
        }
     
        public synchronized int transfert(int qte) {
            // Ne pas enlever les System.out de ce test !
            System.out.print("-("+qte+") dans le vase 1 ");
            vase[0] -= qte;
            System.out.println("+("+qte+") dans le vase 2");
            vase[1] += qte;
            iteration++;
            if( iteration % 1000 == 0)
                System.out.println("\n" + iteration + " ITERATIONS.\n");
            return vase[0]+vase[1];
        }
     
        public class ThreadTransfert extends Thread {
            Random r = new Random();
            int quantite;
            @Override
            public void run() {
                while( !isInterrupted()) {
                    quantite = r.nextInt(11)-6;
                    vase[0] -= quantite;
                    vase[1] += quantite;
                    if( transfert(quantite) != QUANTITE_INITIALE) {
                        System.err.println("Quantité totale invalide à l'itération " + iteration);
                        System.exit(-1);
                    }
     
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {}
                }
            }
        }
    }
    Directement depuis le tuto de Valère.
    Sauf que d'après le tuto je ne devrais jamais avoir d'erreur de vase communiquant.
    Or j'ai toujours un problème avec le synchronized. Problème au sens que l'algorithme ne devrait pas s'arrêter.
    Donc j'ai l'impression que soit j'ai rien compris au synchronized, soit je sais plus écrire, soit y'a une grosse anguille sous roche.

  4. #4
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Le programme a un problème. Les Thread modifient les données du tableau "vase" sans synchronisation juste avant d'appeler la méthode "transfert".
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  5. #5
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 585
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 585
    Par défaut
    Il y a manifestement une erreur dans ce tuto.

    Les lignes :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    vase[0] -= quantite;
    vase[1] += quantite;
    ne devraient apparaître que dans le code synchronisé, pas ailleurs.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  6. #6
    Membre confirmé Avatar de flotho
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Novembre 2006
    Messages
    156
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Novembre 2006
    Messages : 156
    Par défaut
    Ca me rassure.

    Mais ce que je ne comprends pas c'est que
    vase[0] -= quantite;
    vase[1] += quantite;
    sont dans une méthode synchronisée.
    Donc normalement les threads ne devraient pas accéder simultanément à cette méthode.
    Donc il ne devrait pas y avoir de problème?

    Où est ce que je me trompe là?

  7. #7
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

    Informations professionnelles :
    Activité : ingénieur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Chaque Thread modifie d'abord les données du tableau "vase" avant d'appeler la méthode synchronisée.
    Le problème ne vient pas de la méthode "transfert", mais de la modification en dehors de tout bloc synchronisé de "vase".
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  8. #8
    Membre confirmé Avatar de flotho
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Novembre 2006
    Messages
    156
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Novembre 2006
    Messages : 156
    Par défaut
    Ok vu, c'est dans le run que cela pose problème.

    Maintenant que je suis rassuré sur le fonctionnement du tuto, cela m'amène à mon problème particulier. En PJ ma classe qui pose problème.

    L'appel se fait de la façon suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    rectoWebcam = new Webcam(rectoDevice, 1, 640, 480, workPath, "Recto");
    versoWebcam = new Webcam(versoDevice, 1, 640, 480, workPath , "Verso");
    rectoWebcam.start_Webcam();
    versoWebcam.start_Webcam();
    Je ne dois pas accéder simultanément à la capture d'une image au risque de saturer le bus USB et de renvoyer une erreur.
    J'ai donc l'impression qu'il me manque des synchronized par ci par là.
    Pourriez vous m'expliquer mon erreur?
    Fichiers attachés Fichiers attachés

  9. #9
    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,


    Ton code est bien synchronisé, mais sur un lock d'instance :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    synchronized void  capture_frame() throws V4L4JException {
        this.fg.startCapture();
        this.bb = fg.getFrame();
        this.fg.stopCapture();
    }
    Ce qui équivaut en fait à ceci :
    [code]
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    void  capture_frame() throws V4L4JException {
        synchronized (this) {
            this.fg.startCapture();
            this.bb = fg.getFrame();
            this.fg.stopCapture();
        }
    }

    Mais vu que tu manipules deux instances différentes, cela revient à avoir deux synchronisations sur deux locks différents : synchronized(rectoWebcam) et synchronized(versoWebcam).

    Les deux synchronisations sont totalement distinctes, et ne se bloque pas manuellement. En fait cette synchronisation t'empêche uniquement d'appeler la méthode capture_frame() de la même instance depuis deux thread différents, mais elle ne t'empêche pas d'appeler plusieurs fois cette méthode sur des instances différentes (ce qui est ton cas).


    Pour éviter ce genre de problème, il est préférable de définir explicitement un lock unique pour toutes les instances :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    /**
     * On utilise un attribut static comme lock.
     */
    private static final Object CAPTURE_LOCK = new Object();
     
    void  capture_frame() throws V4L4JException {
        synchronized (CAPTURE_LOCK) {
            this.fg.startCapture();
            this.bb = fg.getFrame();
            this.fg.stopCapture();
        }
    }
    Désormais le code de la méthode capture_frame() ne pourra pas du tout être exécutée en parallèle, même si on manipule plusieurs instances...

    a++

  10. #10
    Membre confirmé Avatar de flotho
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Novembre 2006
    Messages
    156
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Novembre 2006
    Messages : 156
    Par défaut
    OOOOKKKKKK!!

    J'avais mal assimilé le fait que le simple synchronized était pour le même thread mais plusieurs instances.

    Si j'ai bien compris, si je veux travailler sur du multithread et du synchronized, il faut que je passe avec un :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    static final mon_gardefou
    . Est ce bien cela?

    Maintenant je me rends compte que cela est quand même bien lent en terme de traitement.
    Les sémaphores sont ils une solution?
    Y'en a t il une autre plsu simple/efficace.

    Merci de tous vos commentaires de qualité!!

  11. #11
    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 flotho Voir le message
    Maintenant je me rends compte que cela est quand même bien lent en terme de traitement.
    Ben... Si tu veux réellement une seule exécution à la fois, je ne vois pas comment tu pourrais faire plus rapide...

    a++

  12. #12
    Membre confirmé Avatar de flotho
    Homme Profil pro
    Architecte de système d'information
    Inscrit en
    Novembre 2006
    Messages
    156
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Pyrénées Orientales (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Architecte de système d'information

    Informations forums :
    Inscription : Novembre 2006
    Messages : 156
    Par défaut
    J'ai une dernière question,

    Sur l'exemple que j'ai posté, comment faire pour que la méthode stop_webcam ne soit pas accessible s'il y a une capture et/ou un enregistrement en cours?

    Suffirait il de reprendre
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    public void stop_webcam() {
            synchronized (CAPTURE_LOCK) {
                this.actif = false;
                this.vd.releaseFrameGrabber();
                this.vd.release();
            }
        }

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

Discussions similaires

  1. strtoul mal compris...
    Par SPACHFR dans le forum Débuter
    Réponses: 5
    Dernier message: 31/05/2007, 16h33
  2. [MySQL] Classe database + connexion multiple + principe mal compris
    Par Rodrigue dans le forum PHP & Base de données
    Réponses: 3
    Dernier message: 14/08/2006, 14h06
  3. [C++]Code mal compris
    Par fafa139 dans le forum MFC
    Réponses: 5
    Dernier message: 11/05/2006, 13h51
  4. [C++]Code mal compris
    Par fafa139 dans le forum C++
    Réponses: 5
    Dernier message: 11/05/2006, 13h51

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