Explorer les Livres électroniques
Catégories
Explorer les Livres audio
Catégories
Explorer les Magazines
Catégories
Explorer les Documents
Catégories
2
1/ Introduction
• La gestion des processus est fondamentale dans un système d’exploitation.
Ce dernier doit permettre entre autres l’allocation des ressources aux
différents processus, leur création, suspension, reprise et terminaison.
• Le processeur est considéré comme le « cerveau » de l’ordinateur.
Composé principalement d’une unité arithmétique et logique (UAL) et d’une
unité de contrôle (ou de commande), il permet d’extraire des instructions de
la mémoire afin de les exécuter.
• L’exécution d’un processus est, en général, une alternance de calculs
effectués par le processeur et de requêtes d’entrée/sortie effectuées par les
périphériques.
3
2/ Définition d’un processus(1)
•Le processus est un concept clé dans un système d’exploitation et
peut être schématisé comme un programme en cours d’exécution.
C’est-à-dire, un programme à l’état actif.
•Un processus représente l’image de l’état du processeur et de la
mémoire au cours de l’exécution d’un programme : le programme
est statique et le processus représente la dynamique de son
exécution.
•Tout processus possède des attributs propres à lui (comme un
numéro d’identification), des ressources qu’il utilise (comme les
fichiers ouverts) et se trouve à tout moment dans un état (par
exemple en exécution ou en attente).
4
2/ Définition d’un processus (2)
•Un processus est constitué de deux parties :
- Un code exécutable du programme en exécution
- Un contexte qui est une image décrivant l’environnement du
processus.
•Un seul processus est exécuté à la fois sur un processeur.
Comme le processeur commute entre les différents processus, on
a une impression de parallélisme mais il s’agit d’un pseudo
parallélisme. Lorsque l'on dispose de plusieurs processeurs, on
exécute plusieurs programmes (processus) en parallèle et c'est un
vrai parallélisme.
•Exemples de processus: Courier électronique, la compression
d’un fichier, le navigateur web, etc. 5
3/ Image mémoire d’un processus
• L’image mémoire (Memory Map) d’un processus représente l’espace
mémoire alloué, qui est composé en plusieurs parties nécessaires au
bon fonctionnement du processus.
• Chaque processus a sa propre image mémoire contenant les
informations suivantes :
9
4/ Structure de données associée au
processus (BCP) (4) Exemple
10
5/ États d'un processus (1)
• Dans un système multitâches, plusieurs processus peuvent se
trouver simultanément en cours d'exécution : ils se partagent
l'accès au processeur, ce qui donne lieu à plusieurs
commutations de contexte.
• Si un système informatique ne comporte qu'un seul processeur,
alors, à un instant donné, un seul processus aura accès à ce
processeur. En conséquence, un processus peut prendre
plusieurs états durant son exécution.
Remarque :
• La multiprogrammation a été introduite en partie pour éviter
qu'un programme en attente de fin d'entrées-sorties ne
monopolise le processeur.
11
5/ États d'un processus (2)
Les trois principaux états d’un processus sont les suivants :
• Etat actif ou élu (running): le processus est en exécution, il
utilise alors le processeur.
• Etat prêt ou éligible (ready): le processus attend la libération du
processeur pour s’exécuter, il pourrait utiliser le processeur s’il
était libre et si c’est son tour.
• Etat en attente ou bloqué : le processus attend une ressource
physique ou logique autre que le processeur pour s’exécuter
(exemple : fin d'une entrée-sortie).
12
5/ États d'un processus (3)
Transitions entre états d’un processus
14
5/ États d'un processus (5)
Exemple
• L’état d’un processus est défini par l’activité courante de celui-ci.
Les processus peuvent interagir entre eux.
• Exemple:
Commande linux: who | wc -l
• Le premier processus qui exécute « who » liste les utilisateurs
connectés et envoie ses résultats dans un tube.
• Le second processus qui exécute « wc -l » compte le nombre de
lignes lui parvenant par le tube.
• Ces deux processus sont lancés de manière concurrente.
Cependant, le processus « wc » peut être prêt à s’exécuter mais il
est obligé d’attendre les informations provenant du processus
« who ». Dans ce cas le processus « wc » se bloque. 15
6/ Mécanisme de commutation de contexte (1)
16
6/ Mécanisme de commutation de contexte (2)
Exemple
17
6/ Mécanisme de commutation de contexte (3)
• Périodiquement, le système d’exploitation décide d’interrompre un
processus pour en exécuter un autre.
• Les étapes du changement de contexte sont les suivantes :
- Suspendre l’exécution du processus P0
- Sauvegarder l’état du processus P0 dans son PCB
- Choisir un nouveau processus P1
- Restaurer le PCB du processus P1
- Démarrer l’exécution du processus P1
• Exemple :
20
#include <windows.h>
#include <stdio.h>
int main( ){
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) ); ZeroMemory( &pi, sizeof(pi)); si.cb = sizeof(si); // Start the child process.
if( !CreateProcess( “Fils.exe”, //nom ou chemin du fichier exécutable
NULL, //Il n’y a pas de ligne de commande.
NULL, // handle de processus non héritant.
NULL, // handle de thread non héritant.
FALSE, // identificateur de l’objet processus/thread non héritant.
0, // Aucun drapeau de création de processus.
NULL, // Utiliser les mêmes chaînes d’environnement que le processus père.
NULL, // Utiliser le répertoire courant du processus père.
&si, // Pointeur sur la structure STARTUPINFO.
&pi ) // Pointeur sur la structure PROCESS_INFORMATION. ) ErrorExit( "CreateProcess failed." );
WaitForSingleObject( pi.hProcess, INFINITE );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread ); return 0; } 21
8/ Processus sous le SE Linux (1)
8.1 Création de processus (1)
• La création d’un nouveau processus sous le système d’exploitation
Linux est réalisée à partir d’un programme en cours d’exécution à
l’aide de la fonction fork( ).
• Le processus d’origine est appelé processus père, et il garde son PID,
et le nouveau processus créé s’appelle processus fils, et possède un
nouveau PID.
• Les caractéristiques de la fonction fork( ) sont les suivantes :
Le processus père et le processus fils ont le même code source mais
ne partagent pas leurs variables au cours d’exécution.
Tout processus Linux (excepté le processus racine) est créé à l’aide
de cet appel système. 22
8/ Processus sous le SE Linux (2)
8.1 Création de processus (2)
A l’issu de l’exécution de l’appel fork( ) par le processus père,
chaque processus reprend son exécution au niveau de l’instruction
suivant le fork( ).
Afin de différencier les traitements à réaliser dans le cas du
processus père et du processus fils, on utilise la valeur de retour de
la fonction fork( ), en utilisant un if et un else ou un switch :
- Si l’appel à fork( ) échoue, le processus fils n’est pas créé et la
valeur de retour est −1.
- Dans le processus fils, la valeur de retour vaut 0.
23
8/ Processus sous le SE Linux (3)
Début et fin d’un processus
Un processus a généralement un début et une fin
Début : création par un autre processus - par fork()
• il existe un processus “primitif” créé à l’origine du système
Fin
• terminaison du processus (à la fin du programme) - par exit()
• destruction par un autre processus - par kill()
• certains processus ne se terminent pas (réalisant des fonctions du
système)
Dans le langage de commande
un processus est créé pour l’exécution de chaque commande
on peut créer des processus pour exécuter des commandes en
(pseudo)-parallèle :
Exemple:
$ prog1 & prog2 &
(deux processus sont créés pour exécuter prog1 et prog2 )
24
8/ Processus sous le SE Linux (4)
Synchronisation entre un processus père et
ses fils
• Le processus fils termine son exécution par exit(statut), où
statut est un code de fin.
• La terminaison du processus père n’entraine pas la
terminaison de ses fils.
• Lorsqu’un processus fils se termine avant son père, il passe à
l’état zombie.
• Un processus zombie ne peut plus s’exécuter, mais consomme
encore des ressources (tables). Il faut éviter de conserver des
processus dans cet état.
25
8/ Processus sous le SE Linux (5)
Synchronisation entre un processus père et
ses fils
• Afin de terminer complètement un processus fils zombie et
donc libérer les ressources associées, le processus père peut
faire appel à une fonction de synchronisation de type wait() ou
waitpid().
26
8/ Processus sous le SE Linux (6)
La fonction wait()
• pid_t wait(int *status) suspend l’exécution du processus père
(appelant) jusqu’à ce que l’un de ses fils se termine.
• La synchronisation du processus père et de l’ensemble de ses fils
nécessite donc autant d’appel à wait() que de processus fils.
• pid_t waitpid(pid_t pid, int *status, int options) permet de
spécifier le PID du fils dont la fin est attendue.
• Le second argument de waitpid() permet de récupérer une
information relative à l’exécution du fils dont on attend la
terminaison.
• Cette information peut être transmise par le processus fils au
moyen de la fonction void exit(int status) qui permet la
terminaison normale du processus.
27
8/ Processus sous le SE Linux (7)
La fonction wait(int *status)
• Valeur de retour :
Si aucun processus fils => -1 ;
Sinon, pid du processus fils s'utilise du coté du processus
père.
• Sémantique :
si aucun des processus fils n'est terminé, le processus père
se bloque.
la fin du blocage arrive soit par la fin d’exécution du
processus fils, soit par une « interruption » du processus père
(réception d'un signal)
28
8/ Processus sous le SE Linux (8)
La fonction waitpid(pid_t pid, int *status,
int options)
• valeur de retour :
• -1 : erreur (pas de fils)
• 0 : échec (il n’existe aucun processus fils terminé)
• >0 : pid d'un fils (zombie) s'il existe
• argument pid (sélection processus à attendre) :
– Si le processus fils mentionné par pid s’est déjà terminé
avant l’appel à cette fonction, il deviendra "zombie"
• options :
• 0 : bloquant
• 1 : non bloquant
29
8/ Processus sous le SE Linux (9)
La fonction exit(int status)
• un appel à la primitive exit() provoque la terminaison du
processus effectuant l’appel avec un code retour status.
• Le père du processus qui effectue un exit reçoit son code retour à
travers un appel à wait.
• Ce code est
- soit constitué à partir de la valeur passée en paramètre à exit par
le fils (terminaison normale du fils (utiliser
WEXITSTATUS(status))).
- soit un code d'erreur fabriqué par le SE (terminaison anormale
du fils) et indiquant la raison de cette terminaison (par exemple
processus tué).
30
8/ Processus sous le SE Linux (10)
Interprétation de la valeur renvoyée par
exit(int status)
• L’interprétation de la valeur récupérée doit, pour des raisons de
portabilité être réalisée par l’intermédiaire de macro-fonctions
prédéfinies dans le fichier d’en-tête <sys/wait.h>.
• Elles sont appelées avec la valeur fournie au retour de l’appel à
wait ou waitpid.
• Exemples:
31
8/ Processus sous le SE Linux (11)
Recouvrement de processus sous Linux
• Le recouvrement de processus permet de remplacer par un autre
code le code exécuté par un processus.
• Le programme et les données du processus sont alors différents,
mais celui-ci garde le même pid, le même père et les même
descripteurs de fichiers.
• C’est ce mécanisme qui est utilisé lorsque, par exemple, nous tapons
la commande ls, ou que nous lançons un programme après l’avoir
compilé:
le terminal de commande dans lequel cette commande est tapée fait
un fork() ;
le processus ainsi créé est recouvert par l’exécutable désiré ;
pendant ce temps, le terminal de commande (le père) attend que le
fils se termine grâce à wait() si la commande n’a pas été lancée en
tâche de fond. 32
8/ Processus sous le SE Linux (12)
La fonction exec
• Il est possible de demander à un processus d’exécuter un autre
programme que son processus père, en utilisant une variante de
la fonction exec (qui remplace le programme courant par un
autre programme).
• Les primitives de recouvrement constituent un ensemble
d’appels système (de type exec*()) permettant à un processus de
charger en mémoire un nouveau code exécutable.
• Le code de remplacement, spécifié comme argument de l’appel
système de type exec*(), écrase le code du processus en cours.
• Des données peuvent être passées au nouveau code exécutable
qui les récupère via les arguments de la fonction exec*() utilisée.
33
La fonction exec
Il existe 6 primitives de recouvrement de type exec*().
• Les deux fonctions de base sont :
– int execl(const char *path, const char *arg0, const char *arg1, ... , const char
*argn, NULL): path est le chemin d’un exécutable à partir du répertoire courant,
arg0, arg1, ... , argn, NULL est la liste des arguments à passer au nouveau
programme.
– int execv(const char *path, const char *argv[]): Le premier paramètre est le
même que celui d’execl et le deuxième paramètre argv[] est un tableau contenant les
arguments à passer au nouveau programme.