Université de Provence MASTER INFORMATIQUE Programmation Parallèle et Distribuée 2010-2011 Programmation Parallèle et Distribuée Partiel jeudi 10 mars 2011 2h00 Aucun document autorisé. Les réponses doivent être argumentées. Les parties sont indépendantes. Le barème est indicatif. Le sujet est composé de 4 pages + 2 pages d annexe. 1 Questions de cours (4,5 points) a) Qu est-ce-qu une machine PRAM? Préciser les différents modes d accès possibles à la mémoire partagée. (1 point) b) Qu est-ce qu un sémaphore? (1 point) c) Expliquer en une douzaine de lignes ce qu est un objet distant et les objectifs et principes de fonctionnement de Java RMI. (1,5 points) d) Quel est le rôle d un rmiregistry? (1 point) 2 Multiplication avec des PRAM (4 points) a) Étant donné un tableau d entiers T de taille n on cherche à calculer la multiplication de tous les éléments du tableau ( n i=1 T [i]). Donner un algorithme CREW efficace en pseudo-code pour une machine PRAM à n processeurs effectuant ce produit. (3 points) b) Quelle est la complexité de votre algorithme de multiplication (donner la complexité avec la notation O)? Quelle est sa complexité totale? (1 point) 1
3 Algorithme Java (6 points) On considère le code java suivant : public c l a s s Mystery extends Thread{ s t a t i c AtomicInteger counter=new AtomicInteger ( 0 ) ; Random r= new Random ( ) ; public Mystery ( ) { / / e n d o r t l e t h r e a d de 1 à 100 m i l l i s e c o n d e s public void pause ( ) { t r y { i n t time=r. n e x t I n t ( 1 0 0 ) + 1 ; sleep ( time ) ; System. out. p r i n t l n ( Temps + time ) ; catch ( InterruptedException i e ){ System. out. p r i n t l n ( Thread interrompu + counter. get ( ) ) ; public void run ( ) { for ( i n t i =0; i <10; i ++){ pause ( ) ; i n t temp=counter. get ( ) ; pause ( ) ; counter. s e t ( temp + 1 ) ; public s t a t i c void main ( S t r i n g [ ] argv ){ Mystery thread1= new Mystery ( ) ; Mystery thread2= new Mystery ( ) ; thread1. s t a r t ( ) ; thread2. s t a r t ( ) ; t r y { thread1. j o i n ( ) ; thread2. j o i n ( ) ; catch ( InterruptedException i e ){ System. out. p r i n t l n ( Thread interrompu + i e ) ; System. out. p r i n t l n ( Valeur f i n a l e : + counter. get ( ) ) ; 2
a) À quoi sert le bloc try dans la fonction main? (1 point) b) Quel est le nombre maximum de Threads pouvant s exécuter en parallèle lors d une exécution de cette fonction sur une machine avec 4 processeurs? (0,5 point) c) Quelle est la valeur maximale que peut afficher cette fonction? (on suppose qu aucun thread ne s arrête prématurément) (2 points) d) Quelle est la valeur minimale que peut afficher cette fonction? (on suppose qu aucun thread ne s arrête prématurément) (2,5 points) 4 Problème du Père Noël (5,5 points) On considère le problème suivant, dit du Père Noël. Le Père Noël dort au Pôle Nord tant qu il n est pas réveillé par ses neuf rênes ou par six de ses dix elfes. A son réveil, il effectue l une des actions suivantes de manière atomique : Si ce sont les rênes qui l ont réveillé, le Père Noël les harnache, remplit le traîneau de jouets et part ensuite les livrer dans le monde entier. Au retour, il permet aux rennes de se mettre en vacances. Si ce sont des elfes qui l ont réveillé, le Père Noël propose de nouvelles idées de jouets à ceux-ci. Les elfes repartent alors fabriquer des jouets avec leurs collègues. Les rênes sont prioritaires sur les elfes. On souhaite créer une classe Java PereNoel permettant de résoudre le problème. Afin de simuler le temps pris par les taches décrites (comme la distribution de jouets) vous pouvez utiliser la fonction pause() de l exercice 3. a) Écrire une méthode réveilparunrenne() qui permet aux rennes de réveiller le Père Noël. La fonction doit être bloquante tant que tous les rennes ne sont pas réunis. (1,5 points) b) Écrire une méthode réveilparunelfe() qui permet aux elfes de réveiller le Père Noël. La fonction doit être bloquante tant que le nombre d elfe requis n est pas atteint. (1,5 points) c) On souhaite maintenant avoir une version distribuée résolvant le problème avec les rennes et elfes en clients et le Père Noël comme serveur. Expliquer en une quinzaine de lignes votre solution. (2,5 points) 5 Liste chainée avec PRAM (exercice bonus) (4 points) Soit L une liste chaînée contenant n objets coloriés soit en bleu, soit en rouge. On souhaite concevoir un algorithme CREW efficace qui sépare les élément bleus des éléments rouge (c est-à-dire qui change le chainage de la liste chainée de départ pour qu elle ne contiennent que des objets bleus). Pour cet algorithme, on supposera que l on a autant de processeurs que la taille de la liste et que chaque processeur a accès à l élément i 3
de la liste avec la liste(i), la couleur de l élément i avec couleur(i) (renvoyant une couleur : bleu ou rouge) et le pointeur de chainage de la liste avec suivant(i) (renvoyant le numéro de l élément suivant) a) Donner le pseudo-code de l algorithme. (3 points) b) Quelle est la complexité de votre algorithme? (donner la complexité avec la notation O) (1 point) 4
Annexe Quelques primitives de synchronisation en Java 1.5 : Thread méthode run() : activité méthode start() : démarrage de l activité static int activecount() : renvoie le nombre de threads actuellement exécutés static int enumerate(thread[] tarray) : stocke l ensemble des threads du même groupe dans le tableau et renvoie le nombre de threads. static Thread currentthread() : renvoie le thread en train d être exécuté. (utile avec Runnable) Semaphore Semaphore(int tickets) : déclare un sémaphore tickets-aire. Semaphore(int permits, boolean fair) : déclare un sémaphore ticketsaire, avec attente (presque) FIFO si fair est true. void acquire() : bloque tant que moins de n threads possèdent un ticket du sémaphore. void acquire(int tickets) : bloque jusqu à ce que moins de n threads possèdent un ticket du sémaphore et consomme tickets tickets de sémaphore. void release() libère un ticket, void release(int tickets) libère tickets tickets. boolean tryacquire() boolean tryacquire(int tickets) boolean tryacquire(long timeout,timeunit unit) boolean tryacquire(int tickets,long timeout,timeunit unit) int getqueuelength() renvoie le nombre de threads en attente, boolean hasqueuedthreads() renvoie true s il y a des threads en attente. Collection<Thread> getqueuedthreads() renvoie la collection des Threads en attente sur ce sémaphore. CyclicBarrier barrière cyclique CyclicBarrier(int parties) : barrière pour parties threads, CyclicBarrier(int parties, Runnable barrieraction) : barrière pour parties threads, barrieraction est exécutée avant de lever la barrière. int await() : attendre que tous les threads aient atteint la barrière. Renvoie le nombre de threads qu il fallait attendre. int await(long timeout, TimeUnit unite) : idem avec un délai d attente de timeout CountDownLatch barrière de type compte à rebours CountDownLatch(int n) crée une barrière avec un compte à rebours commençant à n, void await() attendre que le compte à rebours soit terminé, 5
boolean await(long delai, TimeUnit unit) attendre au plus delai unit que le compte à rebours soit terminé, void countdown() décrémente le compteur. Si 0 est atteint, tous les threads bloqués sont alors libérés, long getcount() renvoie l état du compteur. ArrayBlockingQueue<E> file de taille bornée ArrayBlockingQueue(int capacite) construit une file de taile capacite, ArrayBlockingQueue(int capacite, boolean fair) construit une file de taile capacite et équitable : les accès sont FIFO, void put(e elt) ajoute elt à la file, en attendant si celle-ci est pleine, E take() renvoie le premier élément de la file et le retire, en bloquant tant que la file est vide, E poll(long delai, TimeUnit unit) renvoie le premier élément de la file et le retire, en attendant au plus delai unit, offer(e elt) ajoute elt à la file, en retournant immédiatement sans ajouter si la file est pleine. LinkedBlockingQueue<E> file optionnellement bornée LinkedBlockingQueue() crée une file d attente (de taille maximale Integer.MAX VALUE), LinkedBlockingQueue(int capacite) crée une file d attente de taille maximale capacite éléments, et méthodes identiques. SynchronousQueue<E> file de capacité nulle ( rendez-vous. SynchronousQueue() SynchronousQueue(boolean fair), avec accès FIFO si fair est vrai, même méthodes (certaines sont trivialisées). ConcurrentLinkedQueue<E> file d attente non bornée, threadsafe et sans attente. boolean add(e elt) ajoute elt et renvoie true, E poll() retourne et enlève le premier élément de la file, E peek() retourne sans enlèver le premier élément de la file. Object classe générique héritée par toutes les autres classes. void wait() : met le thread courant en attente jusqu à qu un autre thread appelle la méthode notify() ou notifyall() sur cet objet void notify() : réveille un des threads en attente sur cet objet void notifyall() : réveille tous les threads en attente sur cet objet AtomicInteger classe permettant de faire des opérations sur un entier de manière atomique int get() : récupère la valeur courante void set(int newvalue) : met à jour la valeur avec newvalue) 6