""" 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()