sémaphore sur les compatiments

This commit is contained in:
Rochas
2024-12-09 22:15:57 +01:00
parent 06bf38a576
commit c5e73329b6
7 changed files with 115 additions and 55 deletions

View File

@@ -7,14 +7,13 @@ ainsi que le restaurant, puis on start tous les clients.
Le constructeur Restaurant initialise le Buffet : le Buffet qui initialise dans
son constructeur les 4 Compartiment (poisson, viande, légume et nouille), le
stand de cuisson, le Cusinier, l'Employe_du_buffet. Puis il star en suite start
l'employer du buffet.
l'employé du buffet.
Le run de Client va suivre ces étapes :
(1) Entrer dans le restaurant en vérifiant bien que le restaurant est libre
(2) Prendre une portion de chaque Compartiment du buffet, en vérifiant le
verrou du compartiment est libre avant de lui-même le verrouiller, après
s'être servi il déverrouille fait un notifyAll sur le compartiment pour
réveiller les clients et l'employer du buffet qui pourrait attendre.
sémaphore du compartiment est libre avant de lui-même le verrouiller,
après s'être servi il déverrouille.
Et fais aussi un notify sur le buffet pour que l'employé du buffet
puisse refaire un tour des compartiments.
(3) Cuire au stand, en se synchronisant avec le stand de cuisson.
@@ -22,15 +21,16 @@ Le run de Client va suivre ces étapes :
(5) Sort, en faisant un notifyAll sur le restaurant pour prévenir tout autre
thread client attendant pour entrer
L'employer du buffet fait le tour de chaque Compartiment du Buffet, s'il y a un
L'employé du buffet fait le tour de chaque Compartiment du Buffet, s'il y a un
un compartiment à moins de 100g alors il vérifie qu'il est libre (se met en wait
desus sinon) et le remplit. Après avoir fait un tour il fait sleep sur le buffet,
le buffet le réveillera à chaque fois qu'un client se soit servi.
Difficulté :
Nous n'avons pas vraiment rencontré de difficulté, on a juste eu parfois quelque
oublie (notifyAll manquant par exemple).
On avait aussi commencé dans Stand_de_cuisson par faire une Queue, on a ensuite
On avait commencé dans Stand_de_cuisson par faire une Queue, on a ensuite
décidé de simplement synchroniser le stand de cuisson et le client, qui est au
final beaucoup plus simple, mais le verrou n'est plus équitable, ce n'est plus le
Client qui attend depuis le plus long temps qui est prioritaire.
Pour les compartiments, nous n'avons pas commencé par faire avec un sémaphore mais
nous nous sommes rendus compte que ça pouvait entraîner des problèmes de
synchronisation (par exemple en forçant les client a vider les compartiment)

View File

@@ -18,4 +18,15 @@ public class Buffet {
return compartiment.length;
}
/*
* return true si un des compartiment n'est pas sufisament remplis
*/
public boolean isEmpty(){
boolean b = false;
for(int i = 0; i <compartiment.length; i++){
b= b||(compartiment[i].getQuantite()<100);
}
return b;
}
}

View File

@@ -24,35 +24,51 @@ public class Client extends Thread {
}
}
/*
* Prendre une portion du compartiment i du buffet
* Le client attent que le compartiment soit libre avant de se servir avec un sémaphore.
* Une fois libre il se sers pendant 200 à 300ms
* Il libère le sémaphore et norify avec le buffet pour que l'employer buffet reférifit le buffet
*/
public void prendre_portion(int i){
Compartiment compartiment = this.restaurant.buffet.getCompartiment(i);
synchronized(compartiment){
int r =new Random().nextInt(MAX_PORTION);
Boolean servi = false;
int r =new Random().nextInt(MAX_PORTION);
//int r = Math.max(compartiment.getQuantite(),69); //TODO
while(!servi){
try{
while(r > compartiment.getQuantite() || !compartiment.isLibre()){
compartiment.wait();
compartiment.getSemaphore().acquire();
if(r<=compartiment.getQuantite()){
compartiment.servir(r);
try{
long temps_servir =new Random().nextInt(300 - 200) + 200;
Thread.sleep(temps_servir);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println(this.getNameClient() + " : a pris une portion de " + compartiment.getName() + " " + r);
servi = true;
}
} catch (InterruptedException e){
}catch (Exception e) {
e.printStackTrace();
} finally{
compartiment.getSemaphore().release();
try {
Thread.sleep(100);
} catch (Exception e) {
e.printStackTrace();
}
}
compartiment.setLibre(false);
compartiment.servir(r);
try{
long temps_servir =new Random().nextInt(300 - 200) + 200;
Thread.sleep(temps_servir);
}catch(InterruptedException e){
e.printStackTrace();
}
compartiment.setLibre(true);
System.out.println(this.getNameClient() + " : a pris une portion de " + compartiment.getName());
compartiment.notifyAll();
}
synchronized(this.restaurant.buffet){
this.restaurant.buffet.notify();
}
}
/*
* essaye d'entrer dans le restaurant
* si il n'est pas libre il wait et attend qu'un client sorte
*/
public void entrer(){
synchronized(restaurant){
try{
@@ -67,6 +83,9 @@ public class Client extends Thread {
}
}
/*
* le Thread s'endort pendant 1 à 2 s le temps de manger
*/
public void manger(){
try{
System.out.println(this.getNameClient() + " : mange");
@@ -77,14 +96,24 @@ public class Client extends Thread {
}
}
/*
* le client sort, et fait un notify() sur le restaurant
* (tout les Thread en attente sur le restaurant sont des clients en attente pour entrer
* et qu'un seul client en attente poura entrer, donc ça ne sers à rien de faire un notifyAll)
*/
public void sort(){
synchronized(restaurant){
System.out.println("- " + this.getNameClient() + " : sorti");
restaurant.diminuerClient();
restaurant.notifyAll();
restaurant.notify();
}
}
/*
* faire cuir le plat
* wait en attendant que la place se libère
* une fois la place prise on wait sur le stand et on laisse faire le stand et le cuisinier
*/
public void cuir_au_stand(Stand_de_cuisson stand){
System.out.println(this.getNameClient() + " : attend pour faire cuir son plat");
synchronized(stand){
@@ -92,7 +121,7 @@ public class Client extends Thread {
while(stand.getClient()!=null){
stand.wait();
}
stand.entrerDansLaQueue(this);
stand.faire_cuire(this);
while(stand.getClient()==this){
stand.wait();
}
@@ -103,6 +132,7 @@ public class Client extends Thread {
System.out.println(this.getNameClient() + " : le plat est cuit");
}
public String getNameClient(){
return ("Client " + this.id);
}

View File

@@ -1,13 +1,15 @@
import java.util.concurrent.Semaphore;
public class Compartiment{
protected final int QUANTITE_MAX = 1000;
private int quantite_courant;
private String name;
private boolean libre;
private Semaphore semaphore;
Compartiment(String name){
this.quantite_courant = 200;
this.name = name;
this.libre = true;
this.semaphore=new Semaphore(1);
}
synchronized void remplir(){
@@ -17,7 +19,6 @@ public class Compartiment{
synchronized void servir(int qte){
quantite_courant -= qte;
notifyAll(); //pour que l'employé du buffet vérifit le buffet
}
public int getQuantite(){
@@ -28,11 +29,7 @@ public class Compartiment{
return this.name;
}
synchronized boolean isLibre(){
return this.libre;
}
synchronized void setLibre(boolean libre){
this.libre = libre;
public Semaphore getSemaphore() {
return semaphore;
}
}

View File

@@ -8,6 +8,10 @@ public class Cuisinier extends Thread {
this.stand = stand;
}
/*
* regarde si un client est au stand, si non il s'endort
* si un client est au stand, il fait cuire son plat
*/
public void run(){
synchronized(stand){
while(Thread.currentThread().isDaemon()){
@@ -26,10 +30,14 @@ public class Cuisinier extends Thread {
}
}
/*
* fait cuir le plat du client pendant 200 à 400ms
* une fois fini il indique au stand que la cuisson est fini (qui fait notifyAll aux clients)
*/
public void faire_cuire(Client client){
System.out.println("# Cuisinier : fait cuire le plat de " + client.getNameClient()) ;
try{
long temps_cuire =new Random().nextInt(300 - 100) + 100;
long temps_cuire =new Random().nextInt(400 - 200) + 200;
Thread.sleep(temps_cuire);
}catch(InterruptedException e){
e.printStackTrace();

View File

@@ -2,35 +2,44 @@ public class Employe_du_buffet extends Thread{
public Buffet buffet;
public Employe_du_buffet(Buffet buffet){
this.buffet = buffet;
this.setDaemon(true);
}
/*
* vas faire le tour de tout les buffet
* si un a moins de 100g, si il n'est pas libre il wait dessus, sinon il le remplis
* avant de se réendormir il vérifit qu'aucun compartiment n'as été vidé pendant dans son dot
*/
public void run(){
synchronized(buffet){
while(Thread.currentThread().isDaemon()){
for(int i = 0; i<buffet.length();i++){
Compartiment compartiment = buffet.getCompartiment(i);
while(Thread.currentThread().isDaemon()){
for(int i = 0; i<buffet.length();i++){
Compartiment compartiment = buffet.getCompartiment(i);
try {
compartiment.getSemaphore().acquire();
if(compartiment.getQuantite()<100){
try {
while(!compartiment.isLibre()){
compartiment.wait();
}
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("Employe Buffer : remplie de stand " + compartiment.getName() + ", il ne restait plus que " + compartiment.getQuantite() +" g");
compartiment.remplir();
}
}
try {
buffet.wait();
} catch (Exception e) {
e.printStackTrace();
} finally{
compartiment.getSemaphore().release();
}
}
synchronized(buffet){
if(!this.buffet.isEmpty()){
try {
buffet.wait();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}

View File

@@ -6,18 +6,23 @@ public class Stand_de_cuisson {
this.client_courant = null;
}
public void entrerDansLaQueue(Client client_courant) {
notifyAll(); //pour réveiller de Cuisinier
public void faire_cuire(Client client_courant) {
this.client_courant = client_courant;
notifyAll(); //pour réveiller de Cuisinier (notifyAll car des clients sont aussi en wait sur le stand)
}
public Client getClient() {
return client_courant;
}
/*
* libère la place
* prévient le client en attente que sont plat est fini, et les prochains client que la place est libre
*/
public void cuissonFini(){
this.client_courant = null;
notifyAll(); //prévient le client en attente, et les prochains client
notifyAll();
}
}