ajout de tous les cours et TP préparés cet été
This commit is contained in:
@@ -1,16 +1,95 @@
|
||||
# TD Gestion des processus et des ressources corrigé
|
||||
# Corrigé des exercices — Gestion des processus
|
||||
|
||||
------
|
||||
---
|
||||
|
||||
## 1. QCM
|
||||
|
||||
1. a.
|
||||
2. a.
|
||||
3. c.
|
||||
4. c.
|
||||
5. c.
|
||||
| Question | Réponse | Explication |
|
||||
|----------|---------|-------------|
|
||||
| 1 | **a.** | Le terminal (interpréteur de commandes) permet d'exécuter des commandes système. |
|
||||
| 2 | **a.** | La commande `ps` (process status) affiche les processus sous Linux. |
|
||||
| 3 | **c.** | Un programme peut être exécuté par plusieurs processus simultanément (ex : ouvrir plusieurs fenêtres du même navigateur). |
|
||||
| 4 | **c.** | L'ordonnanceur choisit le processus à exécuter parmi ceux en état "prêt". |
|
||||
| 5 | **c.** | L'interblocage (deadlock) survient quand des processus s'attendent mutuellement pour des ressources. |
|
||||
|
||||
---
|
||||
|
||||
## 2. Questions
|
||||
|
||||
1. Grâce à l'ordonnancement et le découpage des programmes en processus.
|
||||
2. Un processus élu est en cours d'exécution, un prêt est en file d'attente dans l'ordonnanceur.
|
||||
### Question 1
|
||||
|
||||
**Expliquer comment il se fait que l'utilisateur d'un ordinateur a l'impression que les programmes sont exécutés en même temps.**
|
||||
|
||||
L'utilisateur a l'impression que les programmes s'exécutent simultanément grâce à deux mécanismes :
|
||||
|
||||
1. **Le découpage en processus** : Chaque programme est divisé en plusieurs processus (unités d'exécution).
|
||||
|
||||
2. **L'ordonnancement** : Le système d'exploitation utilise un ordonnanceur qui :
|
||||
- Gère une file d'attente des processus prêts à s'exécuter
|
||||
- Alloue le processeur à chaque processus pendant un court laps de temps (quantum)
|
||||
- Effectue des changements de contexte très rapides entre les processus
|
||||
|
||||
3. **La rapidité du processeur** : Le processeur exécute des milliards d'instructions par seconde. Les changements de contexte sont si rapides (quelques millisecondes) que l'utilisateur ne perçoit pas les interruptions.
|
||||
|
||||
**Exemple** : Si le quantum est de 10 ms et qu'il y a 10 processus, chaque processus s'exécute 100 fois par seconde. L'œil humain ne peut pas percevoir ces alternances, d'où l'illusion de simultanéité.
|
||||
|
||||
---
|
||||
|
||||
### Question 2
|
||||
|
||||
**Quelles sont les différences entre les états prêt et élu ?**
|
||||
|
||||
| Critère | État Prêt | État Élu |
|
||||
|---------|-----------|----------|
|
||||
| **Définition** | Le processus attend son tour dans la file d'exécution | Le processus est en cours d'exécution sur le processeur |
|
||||
| **Ressources** | Toutes les ressources nécessaires sont disponibles | Le processeur lui est alloué |
|
||||
| **Position** | Dans la file d'attente de l'ordonnanceur | Sur le processeur (CPU) |
|
||||
| **Nombre** | Plusieurs processus peuvent être prêts | Un seul processus élu par cœur de processeur |
|
||||
| **Transition** | Devient élu quand l'ordonnanceur le choisit | Redevient prêt quand son quantum expire |
|
||||
|
||||
**Schéma des transitions** :
|
||||
```
|
||||
Ordonnanceur choisit
|
||||
[PRÊT] ─────────────────────────────► [ÉLU]
|
||||
▲ │
|
||||
│ Quantum expiré ou │
|
||||
└─────────── interruption ────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Résumé des états d'un processus
|
||||
|
||||
```
|
||||
Création
|
||||
│
|
||||
▼
|
||||
┌──────────┐
|
||||
│ NOUVEAU │
|
||||
└────┬─────┘
|
||||
│ Admission
|
||||
▼
|
||||
Ressource ┌──────────┐ Ordonnancement
|
||||
disponible ◄────│ PRÊT │────────────────────► ┌──────────┐
|
||||
│ └──────────┘ │ ÉLU │
|
||||
│ ▲ └────┬─────┘
|
||||
│ │ Interruption │
|
||||
│ │ (quantum expiré) │
|
||||
│ ┌────┴─────┐ │
|
||||
└───────────►│ BLOQUÉ │◄──────────────────────────┘
|
||||
└──────────┘ Attente ressource
|
||||
│
|
||||
│ Terminaison
|
||||
▼
|
||||
┌──────────┐
|
||||
│ TERMINÉ │
|
||||
└──────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
|
||||
390
Processus/Corrige_TP_Ordonnanceur.py
Normal file
390
Processus/Corrige_TP_Ordonnanceur.py
Normal file
@@ -0,0 +1,390 @@
|
||||
"""
|
||||
Corrigé du TP Simulateur d'Ordonnanceur
|
||||
"""
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 1 : Classe Processus
|
||||
# =============================================================================
|
||||
|
||||
class Processus:
|
||||
"""Représente un processus système."""
|
||||
|
||||
compteur_pid = 0
|
||||
|
||||
def __init__(self, nom, duree_totale, priorite=0):
|
||||
"""
|
||||
Constructeur de la classe Processus.
|
||||
|
||||
:param nom: (str) Nom du processus
|
||||
:param duree_totale: (int) Durée totale d'exécution
|
||||
:param priorite: (int) Priorité (0 = normale)
|
||||
"""
|
||||
Processus.compteur_pid += 1
|
||||
self.pid = Processus.compteur_pid
|
||||
self.nom = nom
|
||||
self.duree_totale = duree_totale
|
||||
self.duree_restante = duree_totale
|
||||
self.etat = "nouveau"
|
||||
self.priorite = priorite
|
||||
self.temps_arrivee = 0
|
||||
self.temps_debut = None
|
||||
self.temps_fin = None
|
||||
|
||||
def executer(self, quantum):
|
||||
"""
|
||||
Exécute le processus pendant quantum unités de temps.
|
||||
|
||||
:param quantum: (int) Temps d'exécution alloué
|
||||
:return: (int) Temps réellement utilisé
|
||||
"""
|
||||
temps_utilise = min(quantum, self.duree_restante)
|
||||
self.duree_restante -= temps_utilise
|
||||
return temps_utilise
|
||||
|
||||
def est_termine(self):
|
||||
"""Vérifie si le processus est terminé."""
|
||||
return self.duree_restante <= 0
|
||||
|
||||
def __repr__(self):
|
||||
return f"[PID {self.pid}] {self.nom} ({self.etat}) - {self.duree_restante}/{self.duree_totale}"
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 2 : Ordonnanceur FIFO
|
||||
# =============================================================================
|
||||
|
||||
class OrdonnanceurFIFO:
|
||||
"""Ordonnanceur First In First Out."""
|
||||
|
||||
def __init__(self):
|
||||
self.file_prets = []
|
||||
self.historique = []
|
||||
self.temps = 0
|
||||
self.processus_termines = []
|
||||
|
||||
def ajouter_processus(self, processus):
|
||||
"""Ajoute un processus à la file."""
|
||||
processus.etat = "pret"
|
||||
processus.temps_arrivee = self.temps
|
||||
self.file_prets.append(processus)
|
||||
print(f"[T={self.temps}] {processus.nom} ajouté (durée: {processus.duree_totale})")
|
||||
|
||||
def executer_suivant(self):
|
||||
"""Exécute le prochain processus jusqu'à la fin."""
|
||||
if len(self.file_prets) == 0:
|
||||
return False
|
||||
|
||||
processus = self.file_prets.pop(0)
|
||||
processus.etat = "elu"
|
||||
processus.temps_debut = self.temps
|
||||
|
||||
print(f"\n[T={self.temps}] >>> {processus.nom} commence")
|
||||
|
||||
while not processus.est_termine():
|
||||
temps_utilise = processus.executer(1)
|
||||
self.temps += temps_utilise
|
||||
self.historique.append(processus.nom[0])
|
||||
|
||||
processus.etat = "termine"
|
||||
processus.temps_fin = self.temps
|
||||
self.processus_termines.append(processus)
|
||||
print(f"[T={self.temps}] <<< {processus.nom} terminé")
|
||||
|
||||
return True
|
||||
|
||||
def executer_tous(self):
|
||||
"""Exécute tous les processus."""
|
||||
print(f"\n{'='*50}")
|
||||
print("ORDONNANCEUR FIFO")
|
||||
print(f"{'='*50}")
|
||||
|
||||
while self.executer_suivant():
|
||||
pass
|
||||
|
||||
self.afficher_resultats()
|
||||
|
||||
def afficher_resultats(self):
|
||||
"""Affiche les résultats de l'ordonnancement."""
|
||||
print(f"\n{'='*50}")
|
||||
print(f"Temps total : {self.temps}")
|
||||
print(f"Diagramme : {''.join(self.historique)}")
|
||||
print(f"{'='*50}")
|
||||
|
||||
print("\nStatistiques par processus :")
|
||||
temps_attente_total = 0
|
||||
temps_rotation_total = 0
|
||||
|
||||
for p in self.processus_termines:
|
||||
rotation = p.temps_fin - p.temps_arrivee
|
||||
attente = rotation - p.duree_totale
|
||||
temps_attente_total += attente
|
||||
temps_rotation_total += rotation
|
||||
print(f" {p.nom}: rotation={rotation}, attente={attente}")
|
||||
|
||||
n = len(self.processus_termines)
|
||||
print(f"\nMoyennes: rotation={temps_rotation_total/n:.1f}, attente={temps_attente_total/n:.1f}")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 3 : Ordonnanceur Round Robin
|
||||
# =============================================================================
|
||||
|
||||
class OrdonnanceurRoundRobin:
|
||||
"""Ordonnanceur Round Robin (tourniquet)."""
|
||||
|
||||
def __init__(self, quantum=2):
|
||||
self.file_prets = []
|
||||
self.quantum = quantum
|
||||
self.temps = 0
|
||||
self.historique = []
|
||||
self.processus_termines = []
|
||||
|
||||
def ajouter_processus(self, processus):
|
||||
"""Ajoute un processus à la file."""
|
||||
processus.etat = "pret"
|
||||
processus.temps_arrivee = self.temps
|
||||
self.file_prets.append(processus)
|
||||
|
||||
def executer_cycle(self):
|
||||
"""Exécute un cycle d'ordonnancement."""
|
||||
if len(self.file_prets) == 0:
|
||||
return False
|
||||
|
||||
processus = self.file_prets.pop(0)
|
||||
processus.etat = "elu"
|
||||
|
||||
if processus.temps_debut is None:
|
||||
processus.temps_debut = self.temps
|
||||
|
||||
temps_utilise = processus.executer(self.quantum)
|
||||
self.temps += temps_utilise
|
||||
|
||||
for _ in range(temps_utilise):
|
||||
self.historique.append(processus.nom[0])
|
||||
|
||||
if processus.est_termine():
|
||||
processus.etat = "termine"
|
||||
processus.temps_fin = self.temps
|
||||
self.processus_termines.append(processus)
|
||||
print(f"[T={self.temps}] {processus.nom} TERMINÉ")
|
||||
else:
|
||||
processus.etat = "pret"
|
||||
self.file_prets.append(processus)
|
||||
print(f"[T={self.temps}] {processus.nom} → file ({processus.duree_restante} restant)")
|
||||
|
||||
return True
|
||||
|
||||
def executer_tous(self):
|
||||
"""Exécute tous les processus."""
|
||||
print(f"\n{'='*50}")
|
||||
print(f"ORDONNANCEUR ROUND ROBIN (quantum={self.quantum})")
|
||||
print(f"{'='*50}\n")
|
||||
|
||||
while self.executer_cycle():
|
||||
pass
|
||||
|
||||
self.afficher_resultats()
|
||||
|
||||
def afficher_resultats(self):
|
||||
"""Affiche les résultats."""
|
||||
print(f"\n{'='*50}")
|
||||
print(f"Temps total : {self.temps}")
|
||||
print(f"Diagramme : {''.join(self.historique)}")
|
||||
print(f"{'='*50}")
|
||||
|
||||
print("\nStatistiques par processus :")
|
||||
temps_attente_total = 0
|
||||
temps_rotation_total = 0
|
||||
temps_reponse_total = 0
|
||||
|
||||
for p in self.processus_termines:
|
||||
rotation = p.temps_fin - p.temps_arrivee
|
||||
attente = rotation - p.duree_totale
|
||||
reponse = p.temps_debut - p.temps_arrivee
|
||||
temps_attente_total += attente
|
||||
temps_rotation_total += rotation
|
||||
temps_reponse_total += reponse
|
||||
print(f" {p.nom}: rotation={rotation}, attente={attente}, réponse={reponse}")
|
||||
|
||||
n = len(self.processus_termines)
|
||||
print(f"\nMoyennes: rotation={temps_rotation_total/n:.1f}, attente={temps_attente_total/n:.1f}, réponse={temps_reponse_total/n:.1f}")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 4 : Ressources et Interblocage
|
||||
# =============================================================================
|
||||
|
||||
class Ressource:
|
||||
"""Représente une ressource partagée."""
|
||||
|
||||
def __init__(self, nom):
|
||||
self.nom = nom
|
||||
self.proprietaire = None
|
||||
|
||||
def est_disponible(self):
|
||||
return self.proprietaire is None
|
||||
|
||||
def acquerir(self, pid):
|
||||
if self.est_disponible():
|
||||
self.proprietaire = pid
|
||||
return True
|
||||
return False
|
||||
|
||||
def liberer(self):
|
||||
self.proprietaire = None
|
||||
|
||||
def __repr__(self):
|
||||
if self.est_disponible():
|
||||
return f"[{self.nom}] LIBRE"
|
||||
return f"[{self.nom}] → PID {self.proprietaire}"
|
||||
|
||||
|
||||
class ProcessusAvecRessources(Processus):
|
||||
"""Processus qui nécessite des ressources."""
|
||||
|
||||
def __init__(self, nom, duree_totale, ressources_requises):
|
||||
super().__init__(nom, duree_totale)
|
||||
self.ressources_requises = ressources_requises
|
||||
self.ressources_obtenues = []
|
||||
|
||||
def demander_ressources(self, ressources_dispo):
|
||||
"""Tente d'obtenir les ressources nécessaires."""
|
||||
for nom_res in self.ressources_requises:
|
||||
if nom_res not in self.ressources_obtenues:
|
||||
ressource = ressources_dispo.get(nom_res)
|
||||
if ressource and ressource.acquerir(self.pid):
|
||||
self.ressources_obtenues.append(nom_res)
|
||||
print(f" ✓ {self.nom} obtient {nom_res}")
|
||||
else:
|
||||
print(f" ✗ {self.nom} BLOQUÉ sur {nom_res}")
|
||||
self.etat = "bloque"
|
||||
return False
|
||||
return True
|
||||
|
||||
def liberer_ressources(self, ressources_dispo):
|
||||
"""Libère toutes les ressources."""
|
||||
for nom_res in self.ressources_obtenues:
|
||||
ressources_dispo[nom_res].liberer()
|
||||
print(f" ○ {self.nom} libère {nom_res}")
|
||||
self.ressources_obtenues = []
|
||||
|
||||
|
||||
def detecter_interblocage(processus_list, ressources):
|
||||
"""Détecte un interblocage."""
|
||||
processus_actifs = [p for p in processus_list if p.etat != "termine"]
|
||||
|
||||
if len(processus_actifs) == 0:
|
||||
return False
|
||||
|
||||
tous_bloques = all(p.etat == "bloque" for p in processus_actifs)
|
||||
|
||||
if tous_bloques:
|
||||
print("\n" + "!"*50)
|
||||
print("!!! INTERBLOCAGE DÉTECTÉ !!!")
|
||||
print("!"*50)
|
||||
for p in processus_actifs:
|
||||
attend = [r for r in p.ressources_requises if r not in p.ressources_obtenues]
|
||||
print(f" {p.nom}: possède {p.ressources_obtenues}, attend {attend}")
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# PARTIE 5 : Comparaison
|
||||
# =============================================================================
|
||||
|
||||
def comparer_ordonnanceurs():
|
||||
"""Compare FIFO et Round Robin."""
|
||||
|
||||
processus_test = [
|
||||
("Navigateur", 8),
|
||||
("Editeur", 4),
|
||||
("Terminal", 2),
|
||||
("Musique", 6)
|
||||
]
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("COMPARAISON FIFO vs ROUND ROBIN")
|
||||
print("="*60)
|
||||
|
||||
# Test FIFO
|
||||
Processus.compteur_pid = 0
|
||||
fifo = OrdonnanceurFIFO()
|
||||
for nom, duree in processus_test:
|
||||
fifo.ajouter_processus(Processus(nom, duree))
|
||||
fifo.executer_tous()
|
||||
|
||||
# Test Round Robin
|
||||
Processus.compteur_pid = 0
|
||||
rr = OrdonnanceurRoundRobin(quantum=2)
|
||||
for nom, duree in processus_test:
|
||||
rr.ajouter_processus(Processus(nom, duree))
|
||||
rr.executer_tous()
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# TESTS
|
||||
# =============================================================================
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
print("="*60)
|
||||
print("TEST 1 : ORDONNANCEUR FIFO")
|
||||
print("="*60)
|
||||
|
||||
Processus.compteur_pid = 0
|
||||
fifo = OrdonnanceurFIFO()
|
||||
fifo.ajouter_processus(Processus("Firefox", 5))
|
||||
fifo.ajouter_processus(Processus("VSCode", 3))
|
||||
fifo.ajouter_processus(Processus("Spotify", 2))
|
||||
fifo.executer_tous()
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("TEST 2 : ORDONNANCEUR ROUND ROBIN")
|
||||
print("="*60)
|
||||
|
||||
Processus.compteur_pid = 0
|
||||
rr = OrdonnanceurRoundRobin(quantum=2)
|
||||
rr.ajouter_processus(Processus("Firefox", 6))
|
||||
rr.ajouter_processus(Processus("VSCode", 4))
|
||||
rr.ajouter_processus(Processus("Spotify", 2))
|
||||
rr.executer_tous()
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("TEST 3 : SIMULATION D'INTERBLOCAGE")
|
||||
print("="*60)
|
||||
|
||||
ressources = {
|
||||
"A": Ressource("A"),
|
||||
"B": Ressource("B")
|
||||
}
|
||||
|
||||
Processus.compteur_pid = 0
|
||||
p1 = ProcessusAvecRessources("Prog1", 5, ["A", "B"])
|
||||
p2 = ProcessusAvecRessources("Prog2", 5, ["B", "A"])
|
||||
|
||||
print("\nÉtat initial des ressources:")
|
||||
for r in ressources.values():
|
||||
print(f" {r}")
|
||||
|
||||
print("\nTour 1: Prog1 demande ses ressources")
|
||||
p1.demander_ressources(ressources)
|
||||
|
||||
print("\nTour 2: Prog2 demande ses ressources")
|
||||
p2.demander_ressources(ressources)
|
||||
|
||||
print("\nTour 3: Prog1 continue")
|
||||
p1.demander_ressources(ressources)
|
||||
|
||||
print("\nTour 4: Prog2 continue")
|
||||
p2.demander_ressources(ressources)
|
||||
|
||||
detecter_interblocage([p1, p2], ressources)
|
||||
|
||||
print("\n" + "="*60)
|
||||
print("TEST 4 : COMPARAISON DES ALGORITHMES")
|
||||
print("="*60)
|
||||
|
||||
comparer_ordonnanceurs()
|
||||
@@ -1,3 +1,5 @@
|
||||
# Exercices — Gestion des processus
|
||||
|
||||
## 1. QCM
|
||||
|
||||
1. Le terminal, interpréteur de commande :
|
||||
@@ -30,7 +32,7 @@
|
||||
|
||||
b. Changer l'état des processus
|
||||
|
||||
c. Choisi le processus à exécuter
|
||||
c. Choisit le processus à exécuter
|
||||
|
||||
5. Un interblocage est :
|
||||
|
||||
@@ -42,5 +44,13 @@
|
||||
|
||||
## 2. Questions
|
||||
|
||||
1. Expliquer comment cela se fait que l'utilisateur d'un ordinateur à l'impression que les programmes sont exécuté en même temps.
|
||||
2. Quels sont les différences entre les états prêt et élu.
|
||||
1. Expliquer comment il se fait que l'utilisateur d'un ordinateur a l'impression que les programmes sont exécutés en même temps.
|
||||
2. Quelles sont les différences entre les états prêt et élu ?
|
||||
|
||||
---
|
||||
|
||||
Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
@@ -1,58 +1,56 @@
|
||||
## Gestion des processus et des ressources
|
||||
# Gestion des processus et des ressources
|
||||
|
||||
|
||||
|
||||
### Le programme
|
||||
## Le programme
|
||||
|
||||

|
||||
|
||||
------
|
||||
|
||||
Nous le savons, un ordinateur possède une architecture de Von Neumann, il y a donc différents composants tels que la mémoire vive, la mémoire 'dure' (Disque dur, SSD...), un processeur...C'est cet élèment ci qui nous intéresse aujourd'hui.
|
||||
Nous le savons, un ordinateur possède une architecture de Von Neumann, il y a donc différents composants tels que la mémoire vive, la mémoire 'dure' (Disque dur, SSD...), un processeur... C'est cet élément-ci qui nous intéresse aujourd'hui.
|
||||
|
||||
Le processeur est le cerveau de l'ordinateur et c'est lui qui exécute les tâches de la machine.
|
||||
|
||||
Comment expliquer que notre processeur arrive à ouvrir un navigateur web, un lecteur de musique, télécharger un jeu ou encore envoyer des messages le tout simultanément. (Sans parler des tâches de fond de l'ordinateur)
|
||||
|
||||
Tout ces programmes sont en réalité des lignes immenses de code et le processeur lui agit seul. Il exécute une à une les instructions de chaque programme, mais donne la sensation de tout gérer en même temps.
|
||||
Tous ces programmes sont en réalité des lignes immenses de code et le processeur, lui, agit seul. Il exécute une à une les instructions de chaque programme, mais donne la sensation de tout gérer en même temps.
|
||||
|
||||
> Les processeurs multi-cœurs fonctionnent de la même façon à l'exception près qu'il n'y a pas 1 cœur, mais 4 voir 8 cœurs. Mais au vu de la multitude de programmes tournant en même temps sur la machine, le nombre de cœurs est nettement inferieur.
|
||||
> Les processeurs multi-cœurs fonctionnent de la même façon à l'exception près qu'il n'y a pas 1 cœur, mais 4 voire 8 cœurs. Mais au vu de la multitude de programmes tournant en même temps sur la machine, le nombre de cœurs est nettement inférieur.
|
||||
|
||||
## 1. Notion de processus
|
||||
|
||||
Lorsqu'un programme est exécuté, il créé plusieurs processus. En effet, un programme est composé de diverses instructions (lignes de code) qui elles mêmes forment diverses parties (processus) de celui-ci.
|
||||
Lorsqu'un programme est exécuté, il crée plusieurs processus. En effet, un programme est composé de diverses instructions (lignes de code) qui elles-mêmes forment diverses parties (processus) de celui-ci.
|
||||
|
||||
Ces processus sont donc stocker dans une file (tout cela est géré par l'OS [Rappel 1ère]) et sont exécuté un à un.
|
||||
Ces processus sont donc stockés dans une file (tout cela est géré par l'OS [Rappel 1ère]) et sont exécutés un à un.
|
||||
|
||||
*Exemple de répartition de deux programmes par l'OS :*
|
||||
|
||||
<img src="assets/file.png" alt="File" style="width:50%;" />
|
||||
|
||||
Chaque processus possèdent différentes informations stockées en mémoire (dans le PCB (*Process Control Block*)) comme :
|
||||
Chaque processus possède différentes informations stockées en mémoire (dans le PCB (*Process Control Block*)) comme :
|
||||
|
||||
| Nom | Description |
|
||||
| ---------- | ----------------------------------------------------- |
|
||||
| PID | Process ID, identifiant du processus |
|
||||
| Etat | Etat du processus |
|
||||
| Registre | Valeur des registres lors de la dernière interruption |
|
||||
| Mémoire | Emplacement mémoire, allouée par le processeur |
|
||||
| Mémoire | Emplacement mémoire alloué par le système |
|
||||
| Ressources | Ressources utilisées par le processus. |
|
||||
|
||||
## 2. Gestion des processus
|
||||
|
||||
Nous l'avons vu chaque processus possèdent plusieurs informations. **L'état** d'un processus permet de comprendre comment la file d'exécution est créée et comment celle-ci perdure.
|
||||
Nous l'avons vu, chaque processus possède plusieurs informations. **L'état** d'un processus permet de comprendre comment la file d'exécution est créée et comment celle-ci perdure.
|
||||
|
||||
Il existe 3 états différents :
|
||||
|
||||
- Prêt : Le processus attend d'être exécuté. Il est dans la file d'exécution.
|
||||
- Elu : En cours d'exécution
|
||||
- Bloqué/En attente : Le processus nécessite une ressource non disponible. Tel qu'un emplacement mémoire, une entré/sortie.
|
||||
- Bloqué/En attente : Le processus nécessite une ressource non disponible, tel qu'un emplacement mémoire ou une entrée/sortie.
|
||||
Lorsque la ressource sera disponible, le processus repassera en état prêt.
|
||||
- On peut imaginer que le processus attend l'intervention de l'utilisateur, ou le chargement d'une ressources (donc d'autres processus), etc.
|
||||
- On peut imaginer que le processus attend l'intervention de l'utilisateur, ou le chargement d'une ressource (donc d'autres processus), etc.
|
||||
|
||||
Il existe aussi deux autres états :
|
||||
|
||||
- Nouveau : le processus vient d'être crée, il n'est pas encore dans la file d'exécution
|
||||
- Nouveau : le processus vient d'être créé, il n'est pas encore dans la file d'exécution
|
||||
- Terminé : l'exécution du processus est finie.
|
||||
|
||||
<u>Voici un schéma des différents états :</u>
|
||||
@@ -61,8 +59,8 @@ Il existe aussi deux autres états :
|
||||
|
||||
## 3. Interblocage :
|
||||
|
||||
L'interblocage intervient lorsque plusieurs processus sont bloqués les un aux autres.
|
||||
Imaginons deux programme.
|
||||
L'interblocage intervient lorsque plusieurs processus sont bloqués les uns par les autres.
|
||||
Imaginons deux programmes.
|
||||
|
||||
```
|
||||
# Programme 1 :
|
||||
@@ -90,7 +88,7 @@ Imaginons deux programme.
|
||||
Accès à la ressource B
|
||||
```
|
||||
|
||||
- Le processus 1 à commencé, via un premier processus. Afin de faire tourner tous les programmes 'en même temps' il repasse dans la file d'exécution
|
||||
- Le processus 1 a commencé, via un premier processus. Afin de faire tourner tous les programmes 'en même temps' il repasse dans la file d'exécution
|
||||
|
||||
```
|
||||
# Programme 2 :
|
||||
@@ -127,14 +125,14 @@ Imaginons deux programme.
|
||||
Accès à la ressource A
|
||||
```
|
||||
|
||||
- Le programme 1 créer un premier processus, qui appelle la ressource A
|
||||
- Le programme 1 crée un premier processus, qui appelle la ressource A
|
||||
|
||||
```
|
||||
# Programme 2 :
|
||||
Accès à la ressource B
|
||||
```
|
||||
|
||||
- le programme 2 créer un premier processus, qui appelle la ressource B
|
||||
- Le programme 2 crée un premier processus, qui appelle la ressource B
|
||||
|
||||
```
|
||||
# Programme 1 :
|
||||
@@ -150,13 +148,13 @@ Imaginons deux programme.
|
||||
|
||||
- Le programme 2 attend la ressource A utilisée par le programme 1 et passe en état bloqué.
|
||||
|
||||
Ici les deux programmes sont en état bloqué car chacun attend la ressource de l'autre. Il y a interblocage et donc aucuns des programmes ne peut s'exécuter.
|
||||
Ici les deux programmes sont en état bloqué car chacun attend la ressource de l'autre. Il y a interblocage et donc aucun des programmes ne peut s'exécuter.
|
||||
|
||||
## 4. En pratique
|
||||
|
||||
### 4. 1. Windows
|
||||
|
||||
Sous windows il est possible de voir les processus en cours d'exécution grâce au **gestionnaire de tâche**. Celui-ci est accessible grâce aux touches Ctrl+ Maj+Echap.
|
||||
Sous Windows il est possible de voir les processus en cours d'exécution grâce au **gestionnaire de tâches**. Celui-ci est accessible grâce aux touches Ctrl+Maj+Echap.
|
||||
Il suffit ensuite d'aller dans l'onglet détail et on obtient tous les processus.
|
||||
|
||||
<img src="assets/liste_processus_windows.png" style="width:60%;" />
|
||||
@@ -169,16 +167,16 @@ Sous linux, il suffit d'accéder au terminal. Et d'y écrire la commande **ps**,
|
||||
|
||||

|
||||
|
||||
### 4.3 MacOs
|
||||
### 4. 3. macOS
|
||||
|
||||
MacOs étant un système Unix, (dérivé de BSD ici) on retrouve les mêmes commandes que sous linux en grande partie.
|
||||
macOS étant un système Unix (dérivé de BSD), on retrouve les mêmes commandes que sous Linux en grande partie.
|
||||
Pour voir les processus, ici, on utilisera plutôt **TOP** (dispo sous linux également donc).
|
||||
|
||||
<img src="assets/top.png" alt="top" style="zoom:50%;" />
|
||||
|
||||
---------
|
||||
|
||||
Auteurs : Florian Mathieu, Timothée Decoster, Enzo Frémaux
|
||||
Auteurs : Florian Mathieu, Enzo Frémeaux, Thimothée Decooster
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
|
||||
503
Processus/TP_Ordonnanceur.md
Normal file
503
Processus/TP_Ordonnanceur.md
Normal file
@@ -0,0 +1,503 @@
|
||||
# TP : Simulateur d'Ordonnanceur — Gestion des Processus
|
||||
|
||||
> **Thème** : Processus, états, ordonnancement, interblocage
|
||||
|
||||
---
|
||||
|
||||
## Contexte
|
||||
|
||||
Votre système d'exploitation préféré gère en permanence des dizaines de processus : navigateur web, lecteur de musique, mises à jour en arrière-plan... Comment fait-il pour donner l'illusion que tout s'exécute en même temps ?
|
||||
|
||||
Dans ce TP, vous allez créer un **simulateur d'ordonnanceur** qui gère une file de processus et les exécute tour à tour, comme le fait un vrai système d'exploitation.
|
||||
|
||||
---
|
||||
|
||||
## Partie 1 : La classe Processus
|
||||
|
||||
### Exercice 1 : Modéliser un processus
|
||||
|
||||
Créez une classe `Processus` représentant un processus avec ses caractéristiques.
|
||||
|
||||
**Attributs :**
|
||||
- `pid` : identifiant unique du processus (int)
|
||||
- `nom` : nom du processus (str)
|
||||
- `duree_totale` : durée d'exécution totale nécessaire (int, en unités de temps)
|
||||
- `duree_restante` : durée restant à exécuter (int)
|
||||
- `etat` : état actuel du processus (str) — "nouveau", "pret", "elu", "bloque", "termine"
|
||||
- `priorite` : niveau de priorité (int, optionnel, par défaut 0)
|
||||
|
||||
**Méthodes :**
|
||||
- `__init__` : constructeur
|
||||
- `executer(quantum)` : exécute le processus pendant `quantum` unités de temps
|
||||
- `est_termine()` : renvoie True si le processus est terminé
|
||||
- `__repr__` : affichage du processus
|
||||
|
||||
```python
|
||||
class Processus:
|
||||
# Compteur de PID (variable de classe)
|
||||
compteur_pid = 0
|
||||
|
||||
def __init__(self, nom, duree_totale, priorite=0):
|
||||
"""
|
||||
Constructeur de la classe Processus.
|
||||
|
||||
:param nom: (str) Nom du processus
|
||||
:param duree_totale: (int) Durée totale d'exécution
|
||||
:param priorite: (int) Priorité (0 = normale)
|
||||
"""
|
||||
Processus.compteur_pid += 1
|
||||
self.pid = Processus.compteur_pid
|
||||
# À compléter
|
||||
pass
|
||||
|
||||
def executer(self, quantum):
|
||||
"""
|
||||
Exécute le processus pendant quantum unités de temps.
|
||||
Met à jour la durée restante.
|
||||
|
||||
:param quantum: (int) Temps d'exécution alloué
|
||||
:return: (int) Temps réellement utilisé
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
|
||||
def est_termine(self):
|
||||
"""
|
||||
Vérifie si le processus est terminé.
|
||||
|
||||
:return: (bool) True si terminé
|
||||
"""
|
||||
# À compléter
|
||||
pass
|
||||
|
||||
def __repr__(self):
|
||||
"""Affichage du processus."""
|
||||
return f"[PID {self.pid}] {self.nom} ({self.etat}) - {self.duree_restante}/{self.duree_totale}"
|
||||
```
|
||||
|
||||
**Tests :**
|
||||
```python
|
||||
>>> p = Processus("Firefox", 10)
|
||||
>>> print(p)
|
||||
[PID 1] Firefox (nouveau) - 10/10
|
||||
>>> p.etat = "elu"
|
||||
>>> p.executer(3)
|
||||
3
|
||||
>>> print(p)
|
||||
[PID 1] Firefox (elu) - 7/10
|
||||
>>> p.est_termine()
|
||||
False
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 2 : L'ordonnanceur FIFO
|
||||
|
||||
### Exercice 2 : Ordonnanceur simple (FIFO)
|
||||
|
||||
L'ordonnanceur **FIFO** (First In, First Out) exécute les processus dans l'ordre d'arrivée, chacun jusqu'à la fin.
|
||||
|
||||
```python
|
||||
class OrdonnanceurFIFO:
|
||||
def __init__(self):
|
||||
"""Initialise l'ordonnanceur avec une file vide."""
|
||||
self.file_prets = [] # File des processus prêts
|
||||
self.historique = [] # Historique d'exécution
|
||||
self.temps = 0 # Temps courant
|
||||
|
||||
def ajouter_processus(self, processus):
|
||||
"""
|
||||
Ajoute un processus à la file des prêts.
|
||||
|
||||
:param processus: (Processus) Processus à ajouter
|
||||
"""
|
||||
processus.etat = "pret"
|
||||
self.file_prets.append(processus)
|
||||
print(f"[T={self.temps}] {processus.nom} ajouté à la file")
|
||||
|
||||
def executer_suivant(self):
|
||||
"""
|
||||
Exécute le prochain processus de la file jusqu'à la fin.
|
||||
"""
|
||||
if len(self.file_prets) == 0:
|
||||
print("File vide, rien à exécuter")
|
||||
return
|
||||
|
||||
# Récupérer le premier processus
|
||||
processus = self.file_prets.pop(0)
|
||||
processus.etat = "elu"
|
||||
|
||||
print(f"\n[T={self.temps}] {processus.nom} commence son exécution")
|
||||
|
||||
# Exécuter jusqu'à la fin
|
||||
while not processus.est_termine():
|
||||
temps_utilise = processus.executer(1)
|
||||
self.temps += temps_utilise
|
||||
self.historique.append((self.temps, processus.pid, processus.nom))
|
||||
|
||||
processus.etat = "termine"
|
||||
print(f"[T={self.temps}] {processus.nom} terminé")
|
||||
|
||||
def executer_tous(self):
|
||||
"""Exécute tous les processus de la file."""
|
||||
print("\n" + "="*50)
|
||||
print("ORDONNANCEUR FIFO - Début de l'exécution")
|
||||
print("="*50)
|
||||
|
||||
while len(self.file_prets) > 0:
|
||||
self.executer_suivant()
|
||||
|
||||
print("\n" + "="*50)
|
||||
print(f"Exécution terminée - Temps total : {self.temps}")
|
||||
print("="*50)
|
||||
|
||||
def afficher_historique(self):
|
||||
"""Affiche l'historique d'exécution."""
|
||||
# À compléter
|
||||
pass
|
||||
```
|
||||
|
||||
**Tests :**
|
||||
```python
|
||||
>>> ordonnanceur = OrdonnanceurFIFO()
|
||||
>>> ordonnanceur.ajouter_processus(Processus("Firefox", 5))
|
||||
>>> ordonnanceur.ajouter_processus(Processus("VSCode", 3))
|
||||
>>> ordonnanceur.ajouter_processus(Processus("Spotify", 2))
|
||||
>>> ordonnanceur.executer_tous()
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 3 : L'ordonnanceur Round Robin
|
||||
|
||||
### Exercice 3 : Ordonnanceur à temps partagé
|
||||
|
||||
L'ordonnanceur **Round Robin** (tourniquet) alloue un **quantum** de temps à chaque processus, puis passe au suivant. Si le processus n'est pas terminé, il retourne en fin de file.
|
||||
|
||||
```python
|
||||
class OrdonnanceurRoundRobin:
|
||||
def __init__(self, quantum=2):
|
||||
"""
|
||||
Initialise l'ordonnanceur Round Robin.
|
||||
|
||||
:param quantum: (int) Temps alloué à chaque processus
|
||||
"""
|
||||
self.file_prets = []
|
||||
self.quantum = quantum
|
||||
self.temps = 0
|
||||
self.historique = []
|
||||
|
||||
def ajouter_processus(self, processus):
|
||||
"""Ajoute un processus à la file."""
|
||||
processus.etat = "pret"
|
||||
self.file_prets.append(processus)
|
||||
|
||||
def executer_cycle(self):
|
||||
"""
|
||||
Exécute un cycle : le premier processus pendant quantum unités.
|
||||
S'il n'est pas terminé, il retourne en fin de file.
|
||||
|
||||
:return: (bool) True si un processus a été exécuté
|
||||
"""
|
||||
if len(self.file_prets) == 0:
|
||||
return False
|
||||
|
||||
# Récupérer le premier processus
|
||||
processus = self.file_prets.pop(0)
|
||||
processus.etat = "elu"
|
||||
|
||||
# Exécuter pendant le quantum
|
||||
temps_utilise = processus.executer(self.quantum)
|
||||
self.temps += temps_utilise
|
||||
|
||||
# Enregistrer dans l'historique
|
||||
for _ in range(temps_utilise):
|
||||
self.historique.append(processus.nom[0]) # Première lettre
|
||||
|
||||
if processus.est_termine():
|
||||
processus.etat = "termine"
|
||||
print(f"[T={self.temps}] {processus.nom} TERMINÉ")
|
||||
else:
|
||||
# Remettre en fin de file
|
||||
processus.etat = "pret"
|
||||
self.file_prets.append(processus)
|
||||
print(f"[T={self.temps}] {processus.nom} interrompu, retour en file ({processus.duree_restante} restant)")
|
||||
|
||||
return True
|
||||
|
||||
def executer_tous(self):
|
||||
"""Exécute tous les processus jusqu'à la fin."""
|
||||
print(f"\n{'='*50}")
|
||||
print(f"ORDONNANCEUR ROUND ROBIN (quantum={self.quantum})")
|
||||
print(f"{'='*50}\n")
|
||||
|
||||
while self.executer_cycle():
|
||||
pass
|
||||
|
||||
print(f"\n{'='*50}")
|
||||
print(f"Temps total : {self.temps}")
|
||||
print(f"Historique : {''.join(self.historique)}")
|
||||
print(f"{'='*50}")
|
||||
```
|
||||
|
||||
**Tests :**
|
||||
```python
|
||||
>>> Processus.compteur_pid = 0 # Reset des PID
|
||||
>>> rr = OrdonnanceurRoundRobin(quantum=2)
|
||||
>>> rr.ajouter_processus(Processus("Firefox", 6))
|
||||
>>> rr.ajouter_processus(Processus("VSCode", 4))
|
||||
>>> rr.ajouter_processus(Processus("Spotify", 2))
|
||||
>>> rr.executer_tous()
|
||||
```
|
||||
|
||||
**Sortie attendue :**
|
||||
```
|
||||
==================================================
|
||||
ORDONNANCEUR ROUND ROBIN (quantum=2)
|
||||
==================================================
|
||||
|
||||
[T=2] Firefox interrompu, retour en file (4 restant)
|
||||
[T=4] VSCode interrompu, retour en file (2 restant)
|
||||
[T=6] Spotify TERMINÉ
|
||||
[T=8] Firefox interrompu, retour en file (2 restant)
|
||||
[T=10] VSCode TERMINÉ
|
||||
[T=12] Firefox TERMINÉ
|
||||
|
||||
==================================================
|
||||
Temps total : 12
|
||||
Historique : FFVVSSFFVVFF
|
||||
==================================================
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 4 : Simulation d'interblocage
|
||||
|
||||
### Exercice 4 : Processus avec ressources
|
||||
|
||||
Modélisons des processus qui ont besoin de ressources partagées.
|
||||
|
||||
```python
|
||||
class Ressource:
|
||||
def __init__(self, nom):
|
||||
"""
|
||||
:param nom: (str) Nom de la ressource
|
||||
"""
|
||||
self.nom = nom
|
||||
self.proprietaire = None # PID du processus qui détient la ressource
|
||||
|
||||
def est_disponible(self):
|
||||
"""Renvoie True si la ressource est libre."""
|
||||
return self.proprietaire is None
|
||||
|
||||
def acquerir(self, pid):
|
||||
"""
|
||||
Tente d'acquérir la ressource.
|
||||
|
||||
:param pid: (int) PID du processus demandeur
|
||||
:return: (bool) True si acquisition réussie
|
||||
"""
|
||||
if self.est_disponible():
|
||||
self.proprietaire = pid
|
||||
return True
|
||||
return False
|
||||
|
||||
def liberer(self):
|
||||
"""Libère la ressource."""
|
||||
self.proprietaire = None
|
||||
|
||||
def __repr__(self):
|
||||
if self.est_disponible():
|
||||
return f"Ressource {self.nom} : LIBRE"
|
||||
else:
|
||||
return f"Ressource {self.nom} : occupée par PID {self.proprietaire}"
|
||||
```
|
||||
|
||||
### Exercice 5 : Détection d'interblocage
|
||||
|
||||
Créez une fonction qui détecte un interblocage potentiel.
|
||||
|
||||
```python
|
||||
class ProcessusAvecRessources(Processus):
|
||||
def __init__(self, nom, duree_totale, ressources_requises):
|
||||
"""
|
||||
:param ressources_requises: (list) Liste des noms de ressources nécessaires
|
||||
"""
|
||||
super().__init__(nom, duree_totale)
|
||||
self.ressources_requises = ressources_requises
|
||||
self.ressources_obtenues = []
|
||||
|
||||
def demander_ressources(self, ressources_dispo):
|
||||
"""
|
||||
Tente d'obtenir toutes les ressources nécessaires.
|
||||
|
||||
:param ressources_dispo: (dict) {nom: Ressource}
|
||||
:return: (bool) True si toutes les ressources obtenues
|
||||
"""
|
||||
for nom_res in self.ressources_requises:
|
||||
if nom_res not in self.ressources_obtenues:
|
||||
ressource = ressources_dispo.get(nom_res)
|
||||
if ressource and ressource.acquerir(self.pid):
|
||||
self.ressources_obtenues.append(nom_res)
|
||||
print(f" {self.nom} obtient {nom_res}")
|
||||
else:
|
||||
print(f" {self.nom} BLOQUÉ sur {nom_res}")
|
||||
self.etat = "bloque"
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def liberer_ressources(self, ressources_dispo):
|
||||
"""Libère toutes les ressources détenues."""
|
||||
for nom_res in self.ressources_obtenues:
|
||||
ressources_dispo[nom_res].liberer()
|
||||
print(f" {self.nom} libère {nom_res}")
|
||||
self.ressources_obtenues = []
|
||||
|
||||
|
||||
def detecter_interblocage(processus_list, ressources):
|
||||
"""
|
||||
Détecte si un interblocage existe.
|
||||
|
||||
:param processus_list: (list) Liste des processus
|
||||
:param ressources: (dict) Dictionnaire des ressources
|
||||
:return: (bool) True si interblocage détecté
|
||||
"""
|
||||
# Un interblocage existe si tous les processus non terminés sont bloqués
|
||||
processus_actifs = [p for p in processus_list if p.etat != "termine"]
|
||||
|
||||
if len(processus_actifs) == 0:
|
||||
return False
|
||||
|
||||
tous_bloques = all(p.etat == "bloque" for p in processus_actifs)
|
||||
|
||||
if tous_bloques:
|
||||
print("\n*** INTERBLOCAGE DÉTECTÉ ! ***")
|
||||
print("Processus bloqués :")
|
||||
for p in processus_actifs:
|
||||
print(f" - {p.nom} : possède {p.ressources_obtenues}, attend {[r for r in p.ressources_requises if r not in p.ressources_obtenues]}")
|
||||
return True
|
||||
|
||||
return False
|
||||
```
|
||||
|
||||
**Exemple de simulation d'interblocage :**
|
||||
```python
|
||||
# Ressources
|
||||
ressources = {
|
||||
"A": Ressource("A"),
|
||||
"B": Ressource("B")
|
||||
}
|
||||
|
||||
# Processus (scénario classique d'interblocage)
|
||||
p1 = ProcessusAvecRessources("Programme1", 5, ["A", "B"])
|
||||
p2 = ProcessusAvecRessources("Programme2", 5, ["B", "A"])
|
||||
|
||||
# Simulation manuelle
|
||||
print("=== Simulation d'interblocage ===\n")
|
||||
|
||||
print("Tour 1 : P1 demande A")
|
||||
p1.demander_ressources(ressources)
|
||||
|
||||
print("\nTour 2 : P2 demande B")
|
||||
p2.demander_ressources(ressources)
|
||||
|
||||
print("\nTour 3 : P1 demande B (déjà pris par P2)")
|
||||
p1.demander_ressources(ressources)
|
||||
|
||||
print("\nTour 4 : P2 demande A (déjà pris par P1)")
|
||||
p2.demander_ressources(ressources)
|
||||
|
||||
# Détection
|
||||
detecter_interblocage([p1, p2], ressources)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Partie 5 : Statistiques et comparaison
|
||||
|
||||
### Exercice 6 : Calcul des métriques
|
||||
|
||||
Ajoutez des méthodes pour calculer les statistiques d'ordonnancement :
|
||||
|
||||
```python
|
||||
def calculer_statistiques(self):
|
||||
"""
|
||||
Calcule les statistiques d'ordonnancement.
|
||||
|
||||
:return: (dict) Statistiques
|
||||
"""
|
||||
# Temps de réponse moyen
|
||||
# Temps d'attente moyen
|
||||
# Temps de rotation moyen
|
||||
# À compléter
|
||||
pass
|
||||
```
|
||||
|
||||
**Métriques importantes :**
|
||||
- **Temps de rotation** (turnaround) : temps total entre l'arrivée et la fin
|
||||
- **Temps d'attente** : temps passé en file d'attente
|
||||
- **Temps de réponse** : temps avant la première exécution
|
||||
|
||||
### Exercice 7 : Comparaison FIFO vs Round Robin
|
||||
|
||||
Créez un programme qui compare les deux algorithmes sur le même jeu de processus.
|
||||
|
||||
```python
|
||||
def comparer_ordonnanceurs():
|
||||
"""Compare FIFO et Round Robin."""
|
||||
|
||||
processus_test = [
|
||||
("Navigateur", 8),
|
||||
("Editeur", 4),
|
||||
("Terminal", 2),
|
||||
("Musique", 6)
|
||||
]
|
||||
|
||||
print("="*60)
|
||||
print("COMPARAISON DES ORDONNANCEURS")
|
||||
print("="*60)
|
||||
|
||||
# Test FIFO
|
||||
Processus.compteur_pid = 0
|
||||
fifo = OrdonnanceurFIFO()
|
||||
for nom, duree in processus_test:
|
||||
fifo.ajouter_processus(Processus(nom, duree))
|
||||
fifo.executer_tous()
|
||||
|
||||
# Test Round Robin
|
||||
Processus.compteur_pid = 0
|
||||
rr = OrdonnanceurRoundRobin(quantum=2)
|
||||
for nom, duree in processus_test:
|
||||
rr.ajouter_processus(Processus(nom, duree))
|
||||
rr.executer_tous()
|
||||
|
||||
# À compléter : afficher la comparaison des statistiques
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Résumé des algorithmes
|
||||
|
||||
| Algorithme | Principe | Avantages | Inconvénients |
|
||||
|------------|----------|-----------|---------------|
|
||||
| **FIFO** | Premier arrivé, premier servi | Simple | Temps d'attente long pour les petits processus |
|
||||
| **Round Robin** | Quantum de temps pour chacun | Équitable, bon temps de réponse | Overhead des changements de contexte |
|
||||
| **Priorité** | Processus prioritaire d'abord | Urgent traité en premier | Famine des processus peu prioritaires |
|
||||
|
||||
---
|
||||
|
||||
## Pour aller plus loin
|
||||
|
||||
- **Ordonnanceur à priorité** : Implémenter un ordonnanceur qui choisit le processus de plus haute priorité
|
||||
- **Ordonnanceur SJF** (Shortest Job First) : Le processus le plus court d'abord
|
||||
- **Vieillissement** (Aging) : Augmenter la priorité des processus qui attendent longtemps
|
||||
- **Interface graphique** : Visualiser l'exécution avec une barre de Gantt
|
||||
|
||||
---
|
||||
|
||||
Auteur : Florian Mathieu
|
||||
|
||||
Licence CC BY NC
|
||||
|
||||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="Licence Creative Commons" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/88x31.png" /></a> <br />Ce cours est mis à disposition selon les termes de la <a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">Licence Creative Commons Attribution - Pas d'Utilisation Commerciale - Partage dans les Mêmes Conditions 4.0 International</a>.
|
||||
Reference in New Issue
Block a user