Devoir Surveillé - Systèmes d'Exploitation I

Qui suis-je ? Question 1 - Identification des commandes Linux L'exercice demande d'associer une description à la commande Linux correspondante. (a) Je suis une commande qui permet de décharger un module en cours d'exécution dans le noyau. Réponse : rmmod (b) Je suis une commande qui envoie un signal à des processus indiqués par leur nom.

D'après le document Devoir Surveillé - Systèmes d'Exploitation I

Cet article a été rédigé automatiquement à partir du document source, puis vérifié avant publication.

Devoir Surveillé - Systèmes d'Exploitation I

Document source

Devoir Surveillé - Systèmes d'Exploitation I

Programming, Operating Systems · PDF · 8 pages · 2018

Afficher l'aperçu du document

Consulter le document original →

Qui suis-je ?

Question 1 - Identification des commandes Linux

L'exercice demande d'associer une description à la commande Linux correspondante.

  • (a) Je suis une commande qui permet de décharger un module en cours d'exécution dans le noyau. Réponse : rmmod
  • (b) Je suis une commande qui envoie un signal à des processus indiqués par leur nom. Réponse : killall
  • (c) Je suis une commande qui affiche le PID d'un processus indiqué par son nom. Réponse : pidof (Note : la lettre figurait probablement à la place des parenthèses vides dans l'énoncé original).
  • (d) Je suis une commande qui liste la taille des différents segments d'un processus. Réponse : size
  • (e) Je suis une commande qui liste les modules en cours d'exécution dans le noyau. Réponse : lsmod

Gestion de processus

Question 2 - Correction des déclarations sur les processus

Il s'agit de corriger les affirmations erronées.

  • (a) Un processus zombie est un processus qui n'a pas lu le code de retour de son père. Correction : Un processus zombie est un processus dont le père n'a pas lu le code de retour. C'est le fils qui est terminé mais qui reste dans la table des processus en attendant que le père lise son état.
  • (b) L'appel système sleep permet d'éviter l'apparition des processus zombies. Correction : L'appel système wait (ou waitpid) permet d'éviter l'apparition des processus zombies.
  • (c) L'appel système getppid affiche le PID du processus petit-fils. Correction : L'appel système getppid retourne le PID du processus père. Note pédagogique : Le corrigé source de l'examen indique de façon erronée "processus grand-père". L'abréviation "ppid" signifie "Parent Process ID" (identifiant du processus père).

Question 3 - Famille nombreuse : génération de n processus

L'objectif est d'écrire un code en C demandant à l'utilisateur un entier n, puis générant n processus.

Le code extrait du document original présente une logique corrompue (les boucles for appelant fork() en boucle infinie ou exponentielle sans arrêt explicite). Pour générer exactement n processus (le père initial + n-1 processus fils), la méthode standard consiste à utiliser l'appel système fork() dans une boucle et à s'assurer que les processus fils sortent de la boucle pour ne pas créer leurs propres fils.

Voici le code corrigé, propre et fonctionnel pour générer n processus au total, en créant n-1 fils à partir d'un seul père :

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main() {
    int i;
    int n;

    printf("n ?\n");
    if (scanf("%d", &n) != 1) {
        return 1; // Sécurité pour la saisie
    }

    // On crée n-1 fils pour avoir n processus au total (avec le père)
    for (i = 1; i < n; i++) {
        if (fork() == 0) {
            // Nous sommes dans le processus fils.
            // On quitte la boucle pour éviter que le fils ne crée d'autres fils.
            break;
        }
    }

    return 0;
}

Question 4 - Arborescences de processus

Il faut proposer les instructions C minimales pour obtenir différentes arborescences.

  • (a) Arborescence : P1 père de P2. Un seul appel suffit :

    fork();
    
  • (b) Arborescence : P1 père de P2, et P2 père de P3. Il faut que le premier fils (P2) exécute un second fork(), mais pas le père (P1).

    if (fork() == 0) fork();
    

    Autre option (évaluation paresseuse) : fork() || fork();

  • (c) Arborescence : P1 père de P2 et de P3. Il faut que le père (P1) exécute les deux fork(), mais que le premier fils (P2) s'arrête.

    if (fork() > 0) fork();
    

    Autre option (évaluation paresseuse) : fork() && fork();

  • (d) Arborescence : P1 père de P2 et P3, et P2 père de P4. L'instruction fork(); fork(); réalise exactement cela.

  1. Le premier fork() crée P2 (depuis P1).
  2. Le second fork() est exécuté par P1 (créant P3) et par P2 (créant P4).
fork();
fork();

Ordonnancement des processus

Question 5 - Algorithme FCFS (First Come, First Served)

Nous disposons d'un seul processeur et de la file d'attente suivante :

  • P1 : Arrivée = 0, Durée = 3
  • P2 : Arrivée = 2, Durée = 6
  • P3 : Arrivée = 4, Durée = 4
  • P4 : Arrivée = 6, Durée = 5
  • P5 : Arrivée = 8, Durée = 2

L'algorithme FCFS (Premier Arrivé, Premier Servi) est non préemptif. Chaque processus s'exécute de bout en bout dans son ordre d'arrivée.

(a) Diagramme de GANTT

  • t = 0 : P1 arrive et s'exécute pour 3 unités. Il finit à t = 3.
  • t = 3 : P2 (arrivé à t = 2) commence et s'exécute pour 6 unités. Il finit à t = 9.
  • t = 9 : P3 (arrivé à t = 4) commence et s'exécute pour 4 unités. Il finit à t = 13.
  • t = 13 : P4 (arrivé à t = 6) commence et s'exécute pour 5 unités. Il finit à t = 18.
  • t = 18 : P5 (arrivé à t = 8) commence et s'exécute pour 2 unités. Il finit à t = 20.
P1 (0 à 3) P2 (3 à 9) P3 (9 à 13) P4 (13 à 18) P5 (18 à 20)

(b) Temps de séjour moyen Le temps de séjour (ou temps de rotation) se calcule comme : Date de fin - Date d'arrivée.

  • P1 : 3 - 0 = 3
  • P2 : 9 - 2 = 7
  • P3 : 13 - 4 = 9
  • P4 : 18 - 6 = 12
  • P5 : 20 - 8 = 12

Somme des temps de séjour = 3 + 7 + 9 + 12 + 12 = 43 Temps de séjour moyen = 43 ÷ 5 = 8.6

(c) Temps d'attente moyen Le temps d'attente se calcule comme : Temps de séjour - Durée d'exécution (ou Date de début - Date d'arrivée).

  • P1 : 3 - 3 = 0
  • P2 : 7 - 6 = 1
  • P3 : 9 - 4 = 5
  • P4 : 12 - 5 = 7
  • P5 : 12 - 2 = 10

Somme des temps d'attente = 0 + 1 + 5 + 7 + 10 = 23 Temps d'attente moyen = 23 ÷ 5 = 4.6

Question 6 - Famine et ordonnancement FCFS

Pourquoi l'ordonnancement FCFS peut-il conduire à la situation de famine ?

Le principe FCFS est un ordonnancement non préemptif (sans réquisition par le système). Si un processus s'accapare le processeur (par exemple, à cause d'une boucle infinie ou d'un bug de conception) et ne le libère jamais volontairement, le système d'exploitation ne reprendra pas la main pour la donner aux autres. Les processus en file d'attente n'obtiendront donc jamais le processeur : c'est la situation de famine.

Méthode

Face à ce type d'épreuve de systèmes d'exploitation, voici les étapes recommandées pour vous assurer un maximum de points :

  1. Arborescences avec fork() : Ne devinez pas le code, tracez-le ! Chaque appel à fork() divise le flux en deux. Dessinez un arbre binaire. Si la condition est if (fork() == 0), seule la branche fils (retour 0) continuera le code dans le bloc. Rappelez-vous que les opérateurs && et || exploitent l'évaluation paresseuse : le second fork() ne s'exécutera que si le résultat du premier le nécessite (faux pour le ET logique, vrai pour le OU logique).
  2. Code système rigoureux : Quand l'énoncé demande de générer des processus, assurez-vous d'éviter les boucles infinies ou les "bombes fork" (fork bombs). Pensez toujours à utiliser un break ou exit() dans le processus fils pour ne pas qu'il participe aux itérations suivantes de la création.
  3. Algorithmes d'ordonnancement : Dessinez le diagramme de Gantt avec précision avant de faire les calculs. L'erreur classique est de confondre la date de début d'un processus avec sa durée. Prenez l'habitude de structurer votre brouillon avec les colonnes suivantes : Processus, Date d'arrivée, Durée, Début réel, Fin réelle, Temps d'attente, Temps de séjour.
  4. Vocabulaire des appels systèmes : Révisez les associations communes (wait avec zombie, fork avec création, exec avec recouvrement). Attention aux pièges : getpid identifie le processus courant, tandis que getppid identifie toujours le parent direct, pas les grands-parents.

Partager

Commentaires

Aucun commentaire pour le moment. Posez la première question.

Les commentaires sont relus avant publication. Votre e-mail n'est jamais affiché.

← Toutes les révisions