simuler un contrôle dans une chaîne de production (c) harold trannois @ u-picardie Première partie =============== Nous allons construire une application de simulation. Plus précisément, il s'agit de simuler un contrôle dans une chaîne de production fictive. Dans cette chaîne, on produit des sacs. En fin de production, chaque sac est contrôlé par des contrôleurs. Dans un premier temps, deux contrôleurs peuvent contrôler simultanément le même sac et tout sac doit être contrôlé par chacun des contrôleurs. Nous considérons qu'il y a dix sacs à vérifier. Questions --------- Définir la classe ControleurSac qui implémente l'interface Runnable. Chaque ControleurSac possède un nom qui est initialisé par un constructeur. La méthode run() est en fait une boucle qui appelle la méthode verifieSac(int) en lui passant un entier représentant le numéro du sac. Cet entier varie de 0 à 9 pour représenter les dix sacs. La méthode verifieSac(int) doit afficher un message indiquant quel vérificateur commence à vérifier quel sac, puis elle doit appeler la méthode sleep en lui passant un entier aléatoire entre 0 et 1000, enfin elle doit afficher un message indiquant quel vérificateur a fini de vérifier quel sac. Construire une classe Simulation qui contient le programme principal main. Ce programme instancie deux vérificateurs, "Ahmed" et "Albert" et lance ces deux vérificateurs chacun dans son propre thread. Deuxième partie =============== Nous allons faire en sorte que deux contrôleurs ne puissent pas accéder simultanément à un même sac. Questions --------- construire la classe Sac doter tout Sac d'un numéro défini à la construction du sac définir la méthode tuEsVerifiePar(ControleurSac). Cette méthode effectue le travail de verifieSac (affichage de message, mise en sommeil, affichage de message). dans la classe Simulation, créer la variable statique lesSacs, tableau de 10 Sacs. modifier la fonction main pour instancier le tableau les Sacs modifier la méthode run() pour envoyer le message tuEsVerifiePar(this) au sac que l'on souhaite vérifier tester en synchronisant ou pas la méthode tuEsVerifiePar(ControleurSac) Dans le cas où on utilise le mot-clef synchronized , on empêche l'accès simultané au même sac par les deux contrôleurs. Vérifier sur les traces d'exécution. Troisième partie ================ une variante de la 2e partie. ----------------------------- Maintenant, nous allons faire en sorte que chaque sac soit vérifié par un et un seul vérificateur. Pour cela, chaque vérificateur teste le Sac. Celui-ci mémorise son état de vérification par une variable booléenne. Ainsi, chaque vérificateur teste la variable du Sac. Si celle-ci a la valeur fausse, il contrôle le Sac, sinon, il passe au suivant. Cette solution est... fausse telle qu'exprimée. En effet, on a encore une fois un problème potentiel d'entrelacement : ahmed teste le sac 0, il constate qu'il doit le vérifier albert teste le sac 0, il constate qu'il doit le vérifier ahmed commence la vérification albert commence la vérification Comme d'habitude, on va confier la responsabilité du contrôle à un objet. Cette fois-ci, nous avons un objet tout trouver pour assumer cette charge : le Sac lui-même. Questions --------- ajouter une variable booléenne dejaVerifie dans la classeSac. dans la méthode tuEsVerifiePar(ControleurSac), ajouter le test de la variable et faire sortir immédiatement de la méthode si cette variable est vraie Quatrième partie ================ Nous allons compliquer le problème : maintenant, il y a un troisième contrôleur : Boris. Boris est le supérieur hiérarchique d'Albert et d'Ahmed et ne vérifie un sac qu'une fois qu'il a été vérifié par Albert ou Ahmed. Encore une fois, il y a plusieurs façons de réaliser cela dans notre programme de simulation. On pourrait par exemple imaginer que le thread de Boris regarde sans arrêt les sacs jusqu'à ce qu'il aient été vérifiés. Cependant, cela est coûteux en temps machine, même si on fait "dormir" le thread entre deux tests sur un sac. L'idéal serait que Boris dise "venez me chercher quand vous aurez fini un sac". C'est ce que permet le mécanisme wait/notify fourni par java. En java, toute instance d'Object (donc tout objet puisque toute classe dérive plus ou moins directement de Object) possède une file d'attente de threads. Un thread T qui a obtenu le verrou de synchronisation sur un Objet A peut demander à être mis dans cette file d'attente. Dans ce cas, il n'est plus "éligible", se met en sommeil (donc ne consomme plus de temps CPU) et le verrou sur A est momentanément rendu. Pour sortir de la file d'attente, il faut qu'un autre thread envoie à l'objet A le message notify ou notifyAll. notify() dit à l'objet de réveiller le premier thread dans sa file d'attente ; ce thread se remet dans l'attente du verrou sur l'objet notifyAll() dit à l'objet de réveiller tous les threads de sa file d'attente et ces threads redemandent le verrou sur l'objet En conséquence, il suffit de mettre un niveau de vérification dans chaque Controleur. La méthode tuEsVerifiePar(Controleur) peut alors faire trois choses : faire un return parce que ce contrôleur n'a plus rien à faire là faire un wait() parce que le sac n'est pas encore prêt pour ce contrôleur faire la vérification habituelle et dans ce cas, faire notify ou notifyAll à la fin Questions --------- ajouter deux paramètres au constructeur de ControleurSac, l'un pour indiquer son niveau, l'autre pour paramètrer la vitesse à laquelle il peut vérifier un Sac ; modifier en conséquence la fonction main pour instancier et lancer un troisième contrôleur du nom de Boris, plus rapide que les autres contrôleurs modifier la méthode tuEsVerifiePar(ControleurSac) pour qu'elle fournisse le comportement décrit ci-dessus