Академический Документы
Профессиональный Документы
Культура Документы
• Introduction
• Les signaux
Introduction
– les signaux,
– les messages.
1
Segments de données et fichiers communs
• Les processus partagent un ensemble de données communes qui sont soit en mémoire
(variables ou segments de données) ou sur disque (fichiers).
• Supposons deux processus qui partagent une variable v. Le premier processus incrémente
de 1 la valeur de v alors que l’autre la décrémente de 1. La valeur initiale de v est 1 :
P1 : v=v+1; P2 : v=v-1;
Supposons que :
• les processus P1 et P2 s’exécutent en temps partagé,
• le processus P1 exécute load v et add 1. Il est suspendu juste après l’exécution de add 1.
• le processus P2 est élu et exécute les instructions load v et sub 1 et store v. Le processus
P2 se termine avec v = 0.
• le processus P1 est ensuite élu et exécute l’instruction store v (v=2).
Génie Informatique Chapitre 4..3
Systèmes d’exploitation
École Polytechnique de Montréal
2
Segments de données et fichiers communs (3)
• Les appels système pour la création de segments partagés sont dans les librairies :
<sys/ipc.h> et <sys/shm.h>.
• L’appel système shmctl permet, entre autres, de détacher un segment d’un processus.
• Les deux programmes suivants communiquent au moyen d’un segment créé par le
premier. Le segment de données est de clé 5. Seuls les processus du groupe peuvent y
accéder. L’accès est exclusif.
• Le premier programme attache le segment créé à son espace de données puis écrit dans
ce segment la valeur 1190. Enfin, il détache après deux secondes le segment de son
espace d’adressage.
3
Segments de données et fichiers communs (5)
// programme shm2.cpp
#include <unistd.h> pascal> shm1 & shm2 &
#include <sys/ipc.h> [4] 10055
#include <sys/shm.h> [5] 10056
#include <iostream.h> status 788889600
int main ( ) status 788889600
{ char * add; entier = 1190
int status, cle = 5;
if( (status = shmget(cle, sizeof(int), 0))==-1)
exit(1);
cout << "status "<< status<< endl;
if((add =(char*) shmat(status,NULL,0)) == (char *) -1)
exit(2);
int* entier= (int *) add;
cout << "entier = " << *entier << endl;
if( shmctl(status, IPC_RMID, NULL) == -1)
exit(3);
exit(0);
}
Les signaux
• Un signal est une interruption logicielle asynchrone qui a pour but d’informer de l’arrivée
d’un événement (outil de base de notification d’évènement). La fonction kill() permet
d’envoyer un signal à un processus.
4
Les signaux (2)
Gestionnaire de signal
• Comme on ne peut pas prévoir à l’avance à quel moment un signal va arriver ni
même s’il doit arriver, une fonction est enregistrée à l’avance pour chaque
signal (gestionnaire de signal).
5
Les signaux (4)
Envoi d’un signal
#include <sys/types.h>
#include <signal.h>
int kill ( pid_t pid, int sig);
6
Les signaux (6)
Capture d’un signal
Signaux fiables et non fiables
• Dans les versions "anciennes" d’Unix le mécanisme des signaux était non
fiable à cause de leur procédure de prise en compte :
– arrivée du signal,
– réinitialisation du mécanisme de capture des signaux
– puis exécution du gestionnaire.
Donc si un second signal arrive entre la réinitialisation et l’appel, le premier
signal est perdu. On parle de conflit d’exécution.
• Un autre jeu de fonctions basé sur la fonction sigaction(2) a été proposé pour
remédier à ce problème.
Génie Informatique Chapitre 4..13
Systèmes d’exploitation
École Polytechnique de Montréal
#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct
sigaction *oldact) ;
7
Les signaux (8)
Attente d’un signal
#include <unistd.h>
int pause (void);
#include <unistd.h>
void sleep (int );
8
Les signaux (10)
Exemple 1 : Échanges de signaux
// signaux1.c
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <wait.h>
static void action(int sig)
{
switch (sig)
{
case SIGUSR1: printf("Signal SIGUSR1 reçu\n");
break;
case SIGUSR2: printf("Signal SIGUSR2 reçu\n");
break;
default: break;
}
}
9
Les signaux (12)
Exemple 1 (complété)
int main()
{ struct sigaction new_action, old_action;
new_action.sa_handler = action;
d5333-09> gcc signaux1.c -o signaux1
sigemptyset (&new_action.sa_mask); d5333-09> signaux1
new_action.sa_flags = 0; Signal SIGUSR2 reçu
int i, pid, etat; Signal SIGUSR1 reçu
if( sigaction(SIGUSR1, &new_action,NULL) <0) Parent : terminaison du fils
perror("Erreur de traitement du code de l' action\n");Parent : fils a terminé
if( sigaction(SIGUSR2, &new_action,NULL) <0)
perror("Erreur de traitement du code de l' action\n");
if((pid = fork()) == 0){ pause();
kill(getppid(), SIGUSR1); // Envoyer signal au parent.
for(;;)
pause(); // Mise en attente d' un signal
}
else {
kill(pid, SIGUSR2); // Envoyer un signal à l' enfant
pause();
printf("Parent : terminaison du fils\n");
kill(pid, SIGTERM); // Signal de terminaison à l' enfant
wait(&etat); // attendre la fin de l'enfant
printf("Parent : fils a terminé\n");
}
} Génie Informatique
Systèmes d’exploitation Chapitre 4..19
École Polytechnique de Montréal
#include <signal.h>
int sigprocmask(
sigset_t* oldset
// oldset reçoit l’ensemble des signaux bloqués avant d’effectuer l’action indiquée par how
);
SIG_BLOCK : pour ajouter les signaux de set à l’ensemble des signaux bloqués.
SIG_UNBLOCK : pour enlever les signaux de set de l’ensemble des signaux bloqués.
SIG_SETMASK : pour remplacer l’ensemble des signaux bloqués par set.
10
Les signaux (14)
Masquage d’un signal
• Lorsqu’un signal bloqué est émis, il est mis en attente jusqu’à ce qu’il
devienne non bloqué.
int main()
{
if( signal(SIGTERM, SIG_IGN) == SIG_ERR)
perror("Erreur de traitement du code de l'
action\n");
if( signal(SIGUSR2, action) == SIG_ERR)
perror("Erreur de traitement du code de l'
action\n");
while (1)
pause();
}
11
bash-2.05b$ gcc -o test-signaux test-signaux.c
bash-2.05b$ ./test-signaux &
[1] 4664
bash-2.05b$ ps
PID TTY TIME CMD
4637 pts/2 00:00:00 bash
4664 pts/2 00:00:00 test-signaux
4665 pts/2 00:00:00 ps
bash-2.05b$ kill -SIGTERM 4664
bash-2.05b$ ps
PID TTY TIME CMD
4637 pts/2 00:00:00 bash
4664 pts/2 00:00:00 test-signaux
4666 pts/2 00:00:00 ps
bash-2.05b$ kill -SIGUSR2 4664
bash-2.05b$ On peut maintenant m' eliminer
bash-2.05b$ ps
PID TTY TIME CMD
4637 pts/2 00:00:00 bash
4664 pts/2 00:00:00 test-signaux
4667 pts/2 00:00:00 ps
bash-2.05b$ kill -SIGTERM 4664
bash-2.05b$ ps
PID TTY TIME CMD
4637 pts/2 00:00:00 bash
4668 pts/2 00:00:00 ps
[1]+ Terminated ./test-signaux
bash-2.05b$
Génie Informatique Chapitre 4..23
Systèmes d’exploitation
École Polytechnique de Montréal
– Ils coûtent chers car ils sont lancés par un appel système, le récepteur
est interrompu, sa pile à l’exécution est modifiée, le gestionnaire prend
la main, la pile à l’exécution est restaurée.
– Ils sont en nombre limité (environ une trentaine dont seulement deux
signaux ne sont pas utilisés par le système lui même).
12
Exercice 1
Le signal SIGCHLD est un signal qui est automatiquement envoyé par le fils à son père lorsque le fils
se termine (par un exit, un return, ou autre).
Ajoutez une fonction et le code nécessaire pour que le père n’attende jamais son fils de façon
bloquante et le fils ne devienne pas zombie.
/*0*/
13
Les tubes anonymes
• Les tubes anonymes (pipes) peuvent être considérés comme des fichiers temporaires.
• Il est caractérisé par deux descripteurs de fichiers (lecture et écriture) et sa taille limitée
(PIPE_BUF) approximativement égale à 4KO.
• L’opération de lecture dans un tube est destructrice : une information ne peut être lue
qu’une seule fois dans un tube.
• Lorsque tous les tous les descripteurs du tube seront fermés, le tube est détruit.
SE
pipe
Flux de données
14
Les tubes anonymes (3)
L’opérateur « | »
• L'opérateur binaire « | » dirige la sortie standard d'
un processus vers l'
entrée
standard d'un autre processus.
Exemple :
• La commande suivante crée deux processus reliés par un tube de communication
(pipe).
who | wc –l
• Les résultats récupérés sur la sortie standard du premier processus sont dirigés vers
l'
entrée standard du deuxième processus via le tube de communication qui les relie.
• Les deux processus s' exécutent en parallèle, les sorties du premier processus sont
stockées dans le tube de communication.
• De façon similaire, lorsque le tube devient vide, le second processus est suspendu
jusqu'
à ce qu'il y ait des données sur le tube.
15
Les tubes anonymes (5)
Création
• Cet appel système crée deux descripteurs de fichiers. Il retourne, dans p, les
descripteurs de fichiers créés :
– p[0] contient le descripteur réservé aux lectures à partir du tube
– p[1] contient le descripteur réservé aux écritures dans le tube.
• Seul le processus créateur du tube et ses descendants (ses fils) peuvent accéder au
tube (duplication de la table des descripteurs de fichiers).
• Si le système ne peut pas créer de tube pour manque d' espace, l'
appel système
pipe() retourne la valeur -1, sinon il retourne la valeur 0.
• L'
accès au tube se fait via les descripteurs (comme pour les fichiers ordinaires).
16
Les tubes anonymes (7)
Création
• Les tubes anonymes sont, en général, utilisés pour la communication entre un
processus père et ses processus fils, avec un processus qui écrit sur le tube, appelé
processus écrivain, et un autre qui lit à partir du tube, appelé processus lecteur.
• La séquence d'
événements pour une telle communication est comme suit :
//programme upipe.c
#include <sys/types.h> //pour les types
#include <unistd.h> //pour fork, pipe, read, write, close
#include <stdio.h> // pour printf
#define R 0
#define W 1
int main ( )
{ int fd[2] ;
pipe(fd) ; // création d'un tube sans nom
char message[100] ; // pour récupérer un message
int nboctets ;
char * phrase = " message envoyé au père par le fils";
if (fork() ==0) // création d'un processus fils
{ close(fd[R]) ; // Le fils ferme le descripteur non utilisé de lecture
// dépôt dans le tube du message
write(fd[W],phrase, strlen(phrase)+1) ;
close (fd[W]) ; // fermeture du descripteur d' écriture
}
Génie Informatique Chapitre 4..34
Systèmes d’exploitation
École Polytechnique de Montréal
17
Les tubes anonymes (9)
Exemple 3 (suite)
else
{ // Le père ferme le descripteur non utilisé d'
écriture
close(fd[W]) ;
// extraction du message du tube
nboctets = read (fd[R], message,100) ;
printf ("Lecture %d octets : %s\n", nboctets, message) ;
// fermeture du descripteur de lecture
close (fd[R]) ;
}
return 0 ;
}
18
Les tubes anonymes (11)
Quelques précisions
#include <unistd.h>
int dup (int desc);
int dup2(int desc1, int desc2);
#include <unistd.h>
int dup (int desc);
int dup2(int desc1, int desc2);
• Ces fonctions peuvent être utilisées pour réaliser des redirections des fichiers
d’entrées et sorties standards vers les tubes de communication.
19
Les tubes anonymes (13)
Exemple 4
• Ce programme réalise l' exécution en parallèle de deux commandes shell. Un tube est
créé pour diriger la sortie standard de la première commande vers l'
entrée standard
de la deuxième.
//programme pipecom.cpp
#include <unistd.h> //pour fork, close…
#include <stdio.h>
#define R 0
#define W 1
int main (int argc, char * argv [ ] )
{ int fd[2] ;
pipe(fd) ; // creation d'
un tube sans nom
char message[100] ; // pour récupérer un message
int nboctets ;
char * phrase = " message envoyé au père par le fils";
if (fork() !=0)
{ close(fd[R]) ; // Le père ferme le descripteur non utilisé de lecture
dup2(fd[W], 1) ; // copie fd[W] dans le descripteur 1)
close (fd[W]) ; // fermeture du descripteur d'écriture
if(execlp(argv[1], argv[1], NULL) ==-1); // exécute le programme écrivain
perror("error dans execlp") ;
}
Génie Informatique Chapitre 4..39
Systèmes d’exploitation
École Polytechnique de Montréal
20
Les tubes anonymes (15)
Exemple 4 (suite)
Processus Processus
STDIN
pipe(fd) STDOUT fork()
STDIN
STDOUT fd[0] pipe
fd[1]
STDIN STDIN
STDOUT pipe
STDOUT
21
Les tubes anonymes (17)
Communication bidirectionnelle
SE pipe
Flux de données
pipe
Flux de données
Exercice 2
22
Génie Informatique Chapitre 4..45
Systèmes d’exploitation
École Polytechnique de Montréal
23
Génie Informatique Chapitre 4..47
Systèmes d’exploitation
École Polytechnique de Montréal
Exercice 3
Considérez le programme suivant qui a en entrée trois paramètres : deux fichiers exécutables et un
nom de fichier. Ce programme crée deux processus pour exécuter les deux fichiers exécutables.
Complétez le code de manière à exécuter, l’un après l’autre, les deux fichiers exécutables et à
rediriger les sorties standards des deux exécutables vers le fichier spécifié comme troisième
paramètre. On récupérera ainsi dans ce fichier les résultats du premier exécutable suivis de ceux du
deuxième.
24
Les tubes nommés
• Les tubes de communication nommés fonctionnent aussi comme des files
de discipline FIFO (first in first out).
• Ils sont plus intéressants que les tubes anonymes car ils offrent, en plus, les
avantages suivants :
– Ils ont chacun un nom qui existe dans le système de fichiers (table des fichiers);
Ils sont considérés comme des fichiers spéciaux ;
– Ils peuvent être utilisés par des processus indépendants ; à condition qu’ils
s’exécutent sur une même machine.
– Ils sont créés par la commande « mkfifo» ou « mknod » ou par l’appel système
mknod( ) ou mkfifo().
#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *nomfichier, mode_t mode) ;
jupiter% ls -l mypipe
prw------- 1 usname grname 0 sep 12 11:10 mypipe
• Une fois le tube créé, il peut être utilisé pour réaliser la communication entre deux
processus.
• Chacun des deux processus ouvre le tube, l’un en mode écriture et l’autre en mode
lecture.
Génie Informatique Chapitre 4..50
Systèmes d’exploitation
École Polytechnique de Montréal
25
Les tubes nommés (3)
Exemple 5 : programme writer
26
Les tubes nommés (5)
Exécution des programmes writer et reader
• Après avoir compilé séparément les deux programmes, il est
possible de lancer leurs exécutions en arrière plan.
27
Les tubes nommés (7)
Quelques précisions
• Si un processus ouvre un tube nommé en lecture (resp. écriture) alors qu’il n’y
a aucun processus qui ait fait une ouverture en écriture (resp. lecture).
-> le processus sera bloqué jusqu’à ce qu’un processus effectue une
ouverture en écriture (resp. en lecture).
/* processus 1 */ /* processus 2 */
VOID main(VOID)
{
CHAR chBuf[BUFSIZE];
DWORD dwRead, dwWritten;
HANDLE hStdin, hStdout;
BOOL fSuccess;
Récupérer les handles
de l’entrée et de la
hStdout = GetStdHandle(STD_OUTPUT_HANDLE); sortie standards
hStdin = GetStdHandle(STD_INPUT_HANDLE);
courantes
if ((hStdout == INVALID_HANDLE_VALUE) || (hStdin == INVALID_HANDLE_VALUE))
ExitProcess(1);
28
Les tubes de communication de Windows (2)
Tubes anonymes
STDIN STDOUT
Fils
for (;;)
{
// Read from standard input.
fSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
if (! fSuccess || dwRead == 0)
break;
29
Les tubes de communication de Windows (4)
Tubes anonymes
// Initialisation de SECURITY_ATTRIBUTES. Le fils va hériter certains
saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); handles du père
saAttr.bInheritHandle = TRUE;
saAttr.lpSecurityDescriptor = NULL;
// récupérer le handle du STDOUT actuel. La création d’un
hStdout = GetStdHandle(STD_OUTPUT_HANDLE); premier tube de
taille par défaut.
// Créer un tube pour le STDOUT du processus enfant.
if (! CreateTube(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
ErrorExit("Stdout tube creation failed\n");
// Le processus enfant a juste besoin d’écrire sur le tube STDOUT.
// Ne pas lui faire hériter son handle de lecture
SetHandleInformation( hChildStdoutRd, HANDLE_FLAG_INHERIT, 0);
// Créer un tube pour le STDOUT du processus enfant.
if (! CreateTube(&hChildStdinRd, &hChildStdinWr, &saAttr, 0)) La création d’un
ErrorExit("Stdin tube creation failed\n"); second tube de
// Le processus enfant a juste besoin de lire sur le tube STDIN. taille par défaut.
// Ne pas lui faire hériter son handle d’écriture.
SetHandleInformation( hChildStdinWr, HANDLE_FLAG_INHERIT, 0);
30
Les tubes de communication de Windows (6)
Tubes anonymes
BOOL CreateChildProcess()
{
PROCESS_INFORMATION piProcInfo;
STARTUPINFO siStartInfo;
BOOL bFuncRetn = FALSE;
// Initialiser la structure PROCESS_INFORMATION.
ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
if (bFuncRetn == 0)
ErrorExit("CreateProcess failed\n");
else
{
CloseHandle(piProcInfo.hProcess);
CloseHandle(piProcInfo.hThread);
return bFuncRetn;
}
}
Génie Informatique Chapitre 4..62
Systèmes d’exploitation
École Polytechnique de Montréal
31
Les tubes de communication de Windows (8)
Tubes anonymes
VOID WriteToTube(VOID)
{
DWORD dwRead, dwWritten;
CHAR chBuf[BUFSIZE];
32
Les tubes de communication de Windows (10)
Tubes anonymes
VOID ErrorExit (LPTSTR lpszMessage)
{
fprintf(stderr, "%s\n", lpszMessage);
ExitProcess(0);
}
Fichier en paramètre
STDIN
STDIN Tube 2 Fils
Pere
=Clavier STDERR
=Écran
STDOUT
Tube 1
STDOUT + STDERR
= Écran
Génie Informatique Chapitre 4..65
Systèmes d’exploitation
École Polytechnique de Montréal
VOID InstanceThread(LPVOID);
VOID GetAnswerToRequest(LPTSTR, LPTSTR, LPDWORD);
int _tmain(VOID)
{
BOOL fConnected;
DWORD dwThreadId;
HANDLE hTube, hThread;
LPTSTR lpszTubename = TEXT("\\\\.\\tube\\mynamedtube");
33
Les tubes de communication de Windows (12)
Tubes nommés
hTube = CreateNamedTube(
lpszTubename, // nom du tube
TUBE_ACCESS_DUPLEX, // accès read/write
TUBE_TYPE_MESSAGE | // tube de type-messages
TUBE_READMODE_MESSAGE | // mode message-read
TUBE_WAIT, // mode bloquant
TUBE_UNLIMITED_INSTANCES, // nb max. d’instances
BUFSIZE, // taille du output buffer
BUFSIZE, // taille du input buffer
NMPWAIT_USE_DEFAULT_WAIT, // time-out du client
NULL); // sécurité par défault
if (hTube == INVALID_HANDLE_VALUE)
{ printf("CreateTube failed");
return 0;
}
34
Les tubes de communication de Windows (14)
Tubes nommés
VOID InstanceThread(LPVOID lpvParam)
{ TCHAR chRequest[BUFSIZE];
TCHAR chReply[BUFSIZE];
DWORD cbBytesRead, cbReplyBytes, cbWritten;
BOOL fSuccess;
HANDLE hTube;
35
Les tubes de communication de Windows (16)
Tubes nommés
VOID GetAnswerToRequest( LPTSTR chRequest, LPTSTR chReply, LPDWORD pchBytes)
{
_tprintf( TEXT("%s\n"), chRequest );
lstrcpy( chReply, TEXT("Default answer from server") );
*pchBytes = (lstrlen(chReply)+1)*sizeof(TCHAR);
}
36
Les tubes de communication de Windows (18)
Tubes nommés
while (1)
{ hTube = CreateFile(
lpszTubename, // nom du tube
GENERIC_READ | // accès read et write
GENERIC_WRITE,
0, // non partagé
NULL, // sécurité par défault
OPEN_EXISTING, // ouvrir un tube existant
0, // attributs par défault
NULL); // pas de fichier template
37