ynchronizedaitotifyotifyAllfsystemutrintrintln

Planche 1

Inf 431 -- Cours 10
Processus et concurrence


http://jeanjacqueslevy.net
secrétariat de l'enseignement:
Catherine Bensoussan
cb@lix.polytechnique.fr
Aile 00, LIX,
01 69 33 34 67
http://www.enseignement.polytechnique.fr/informatique/IF

Planche 2

Plan


.7@percent
  1. Création de processus
  2. Terminaison
  3. Variables partagées
  4. Atomicité et sections critiques
  5. Interblocage
  6. Famine
  7. Synchronisation par variables de condition

Planche 3

Concurrence (1/2)

Mais il faut :
Planche 4

Concurrence (2/2)

Planche 5

Processus (1/6)

Un processus (Thread) est un programme qui s'exécute.
class Code implements Runnable {

  public void run () {
    while (true) {
      System.out.println ("Bonjour de " + Thread.currentThread());

  } }

  public static void main (String[ ] args) {
    Code p = new Code();
    Thread t1 = new Thread(p);
    Thread t2 = new Thread(p);
    t1.start(); t2.start();
} } Exécution

Planche 6

Processus (2/6)

Un processus (Thread) est un programme qui s'exécute.
class Code implements Runnable {

  public void run () {
    while (true) {
      System.out.println ("Bonjour de " + Thread.currentThread());
      Thread.yield();
  } }

  public static void main (String[ ] args) {
    Code p = new Code();
    Thread t1 = new Thread(p);
    Thread t2 = new Thread(p);
    t1.start(); t2.start();
} } Exécution

Planche 7

Processus (3/6)

En Java
Planche 8

Processus (4/6)

Le même exemple en programmation par objets.
class Code1 extends Thread {

  public void run () {
    while (true) {
      System.out.println ("Bonjour de " + this);
      Thread.yield();
    }
  }

  public static void main (String[ ] args) {
    Thread t1 = new Code1();
    Thread t2 = new Code1();
    t1.start(); t2.start();
  }
Exécution

Plus simple,
mais moins de latitude dans la hiérarchie des classes.


Planche 9

Processus (5/6)

Planche 10

Processus (6/6)

Planche 11

Terminaison (1/3)


class Exemple1 implements Runnable {

  public void run () {
    try {
      while (true) {
        System.out.println ("Bonjour de " + Thread.currentThread());
        Thread.sleep(1000);
      }
    } catch (InterruptedException e) { }
  }

  public static void main (String[ ] args) {
    Thread t = new Thread(new Exemple1());
    t.start();
    t.interrupt();
  }
}

Un processus t est souvent un programme qui ne s'arrête jamais.

On peut l'interrompre: t doit alors gérer sa propre terminaison. Ainsi les invariants sont préservés.


Planche 12

Terminaison (2/3)


class Exemple2 extends Thread {

  public void run () {
    while (!isInterrupted()) {
      System.out.println ("Bonjour de " + this);
    }
  }

  public static void main (String[ ] args) {
    Thread t = new Exemple2();
    t.start();
    t.interrupt();
  }
Exécution

Un processus teste périodiquement s'il n'est pas interrompu.

Planche 13

Terminaison (3/3)


class Exemple3 extends Thread {

  public void run () {
    System.out.println ("Bonjour de " + this);
  }

  public static void main (String[ ] args)
    throws InterruptedException {
    Thread t = new Exemple3();
    t.start();
    t.join(0);
  }
Exécution

On peut attendre la fin d'un processus en précisant un délai maximum d'attente en argument de join en millisecondes (0 = délai infini).

La méthode join lance une exception si un autre processus a interrompu le processus courant.


Planche 14

Variables partagées (1/2)

Une même variable x peut être modifiée par deux processus.
class P1 extends Thread {
  public void run () {
    while (true) {
      P.x = 23;
      Thread.yield();
} } }
class P2 extends Thread {
  public void run () {
    while (true) {
      P.x = 7;
      Thread.yield();
} } }

class P {
  static int x = 0;

  public static void main (String[ ] args)
    throws InterruptedException {
    Thread t1 = new P1(), t2 = new P2();
    t1.start(); t2.start(); 
    while (true) {
      System.out.println (x); // ----------------- Valeur de x?
      Thread.sleep (1000);
} } } Exécution

Planche 15

Variables partagées (2/2)

Planche 16

Atomicité et sections critiques (1/5)

Planche 17

Atomicité et sections critiques (2/5)

Planche 18

Atomicité et sections critiques (3/5)

Planche 19

Atomicité et sections critiques (4/5)

Planche 20

Atomicité et sections critiques (5/5)

Planche 21

Interblocage

Exercice 1 Faire un exemple d'interblocage avec des appels sur des méthodes synchronisées.

Planche 22

Famine

Planche 23

Conditions (1/7)

Planche 24

Conditions (2/7)

Planche 25

Conditions (3/7)


static void ajouter (int x, FIFO f) throws InterruptedException {
  synchronized (f) {
    while (f.pleine)
      f.wait();
    f.contenu = x;
    f.pleine = true;
    f.notify();
} }

static int supprimer (FIFO f) throws InterruptedException {
  synchronized (f) {
    while (!f.pleine)
      f.wait();
    f.pleine = false;
    f.notify();
    return f.contenu;
} } Exécution
Planche 26

Conditions (4/7)


synchronized void ajouter (int x) throws InterruptedException {
    while (pleine)
      wait();
    contenu = x;
    pleine = true;
    notify();
}

synchronized int supprimer () throws InterruptedException {
    while (!pleine)
      wait();
    pleine = false;
    notify();
    return contenu;
Exécution
Planche 27

Conditions (5/7)


synchronized void ajouter (int x) throws InterruptedException {
    while (pleine)
      wait();
    contenu = x;
    pleine = true;
    notifyAll();
}

synchronized int supprimer () throws InterruptedException {
    while (!pleine)
      wait();
    pleine = false;
    notifyAll();
    return contenu;
Exécution
Planche 28

Conditions (6/7)

Planche 29

Conditions (7/7)


class FIFO {
  int debut, fin; boolean pleine, vide; int[ ] contenu;
  ...
  synchronized void ajouter (int x) throws InterruptedException {
    while (pleine)
      wait();
    contenu[fin] = x;
    fin = (fin + 1) % contenu.length;
    vide = false; pleine = fin == debut;
    notifyAll();
  }

  synchronized int supprimer () throws InterruptedException {
    while (vide)
      wait();
    int res = contenu[debut];
    debut =  (debut + 1) % contenu.length;
    vide = fin == debut; pleine = false;
    notifyAll();
    return res;
  } Exécution

Planche 30

Exercices

Exercice 2 Donner un exemple précis où notifyAll fait une différence avec notify.

Exercice 3 Expliquer dans le détail pourquoi l'action notify doit se faire en section critique. Que se passerait-il si l'instruction était faite en dehors de la section critique?

Exercice 4 Faire l'exemple de la file d'attente avec la représentation en liste d'éléments.

Exercice 5 Programmer des piles concurrentes.

Exercice 6 Montrer que le réveil des processus n'est pas forcément dans l'ordre premier en attente, premier réveillé.

Exercice 7 Donner un exemple où un processus peut attendre un temps infini avant d'entrer en section critique.

Exercice 8 Comment programmer un service d'attente où les processus sont réveillés dans l'ordre d'arrivée.





This document was translated from LATEX by HEVEA.