111 lines
2.7 KiB
Python
111 lines
2.7 KiB
Python
#!/usr/bin/env python
|
|
# -*- coding: utf-8 -*-
|
|
"""Un exemple d'utilisation de sémaphores pour synchroniser des tâches.
|
|
|
|
Ce code définit 4 tâches qui devront être exécutées selon la relation
|
|
de précédence suivante :
|
|
|
|
T1 < T2, T1 < T3, T2 < T4, T3 < T4
|
|
|
|
Le graphe de précédence pour ces tâches forme donc un diamant :
|
|
|
|
+-----> T2 -----+
|
|
| |
|
|
| \/
|
|
T1 T4
|
|
| /\
|
|
| |
|
|
+-----> T3 -----+
|
|
|
|
Ce fichier montre l'utilisation de sémaphores pour assurer l'exécution
|
|
de ces 4 tâches dans un ordre qui satisfait cette spécification de
|
|
précédence.
|
|
|
|
|
|
Cours « Systèmes d'exploitation ».
|
|
|
|
Sergiu Ivanov <sergiu.ivanov@univ-evry.fr>
|
|
|
|
"""
|
|
|
|
# La librairie de gestion de fils d'exécution.
|
|
import threading
|
|
|
|
|
|
# Définir 4 sémaphores, un par tâche.
|
|
t1_finie = threading.Semaphore();
|
|
t2_finie = threading.Semaphore();
|
|
t3_finie = threading.Semaphore();
|
|
t4_finie = threading.Semaphore();
|
|
|
|
# Le sémaphore ti_finie est relâché à la fin de la tâche Ti. Il est
|
|
# donc nécessaire de les acquérir tous au début.
|
|
t1_finie.acquire();
|
|
t2_finie.acquire();
|
|
t3_finie.acquire();
|
|
t4_finie.acquire();
|
|
|
|
|
|
# Nos tâches.
|
|
#
|
|
# Chaque tâche commence par vérifier que les tâches dont elle dépend
|
|
# ont fini leur exécution. À la fin de l'exécution, chaque tâche
|
|
# relâche le sémaphore qui lui est associé.
|
|
|
|
def t1():
|
|
# Tâche initiale, aucune vérification.
|
|
|
|
print("Ceci est la tâche T1")
|
|
|
|
t1_finie.release();
|
|
|
|
def t2():
|
|
# Cette opération sera bloquée si le sémaphore t1_finie n'est pas
|
|
# encore relâché.
|
|
t1_finie.acquire();
|
|
|
|
# Si nous sommes arrivés ici, nous savons que le sémaphore
|
|
# t1_finie a été relâché. Ne le gardons pas pris, relâchons-le
|
|
# pour que les autres puissent avoir les signal.
|
|
t1_finie.release();
|
|
|
|
print("Ceci est la tâche T2")
|
|
|
|
t2_finie.release();
|
|
|
|
def t3():
|
|
t1_finie.acquire();
|
|
t1_finie.release();
|
|
|
|
print("Ceci est la tâche T3")
|
|
|
|
t3_finie.release();
|
|
|
|
def t4():
|
|
# La tâche T4 dépend des tâches T3 et T4 ; on vérifiera donc deux
|
|
# sémaphores.
|
|
t2_finie.acquire();
|
|
t2_finie.release();
|
|
|
|
t3_finie.acquire();
|
|
t3_finie.release();
|
|
|
|
print("Ceci est la tâche T4")
|
|
|
|
t4_finie.release();
|
|
|
|
|
|
# Créer un objet Thread (fil d'exécution) pour chacune de nos tâches.
|
|
#
|
|
# Les fils ne sont pas encore lancés.
|
|
t1_thread = threading.Thread(target = t1)
|
|
t2_thread = threading.Thread(target = t2)
|
|
t3_thread = threading.Thread(target = t3)
|
|
t4_thread = threading.Thread(target = t4)
|
|
|
|
# Lancer les fils d'exécution dans un ordre quelconque, pas
|
|
# nécessairement correspondant au graphe de précédence exigé.
|
|
t4_thread.start()
|
|
t3_thread.start()
|
|
t2_thread.start()
|
|
t1_thread.start()
|