Le but de ce travail pratique est de “copier” l’API de la librairie
standard de std::thread::spawn(). Ainsi l’appel à
spawn() pourrait avoir l’air de
Runtime::spawn(move || {
// do some cool stuff with the environement
});Pour ce faire, il faudra faire plusieurs modification au code que nous avons construit en cours.
Lors de l’appel à spawn() on passe en argument une
fonction de type fn() avec la fonction
fn spawn<F: FnOnce() + 'static>(f: F);où on voit que la fonction fn() est remplacée par
n’importe quelle fermeture (closure) dont la durée de vie est statique
(a la durée de vie du programme).
L’appel à spawn() ne prend plus self en
argument
Il faut ajouter un thread thread_ptr à la struct
ThreadContext qui va permettre d’enregistrer l’adresse de
la fonction passée en argument et permettre son exécution.
Il faut ajouter un membre task de type
Option<Box<dyn FnOnce>> au type
Thread, ansi qu’un id: usize pour identifier
les threads.
Il faut remplacer la fonction f() dans l’appel à
write() par l’appel à une fonction
call(thread: u64) qui à partir du thread_ptr
va appeler la bonne tâche.
La fonction switch doit prendre en compte l’ajout de
tread_ptr après le dernier mov
Pour bien voir quand les threads se terminent, modifiez la
fonction guard() pour qu’on affiche l’id du
thread.
Modifier également la fonction run() pour qu’elle ne
prenne plus self en argument.
Le main() de votre programme peut ressembler à cela:
fn main() {
let mut runtime = Runtime::new();
runtime.init();
for num in 0..MAX_THREADS - 2 {
Runtime::spawn(move || {
println!("Starting thread {}", num + 1);
for i in 0..10 {
println!("Thread num {num}, counter {i}");
yield_thread();
}
Runtime::spawn(move || {
println!("Spawned thread num {num}");
});
});
}
Runtime::run();
}Rendre le scheduler un peu plus équitable. Choisir le prochain thread à exécuter en fonction du temps que chaque thread a déjà passé à être exécuté. De tous les threads prêts prendre celui qui a été exécuté le moins longtemps depuis le début de l’exécution.