A 2015, AG 2021JLA 2015, AG 2021
Processus et gestion de processus
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Communications entre processus Signaux
Tubes
Tubes nommés
UNIX – GNU/Linux
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Communication entre processus
La communication entre processus est un problème courant dans les systèmes
d'exploitation multiprogrammé
Plusieurs processus concourent à la
réalisation d'une même tâche pour cela ils doivent :
Partager l'utilisation d'une
ressource : une variable, un tampon, un fichier, une base de données … cette ressource étant évidemment non partageable
Échanger des données : valeur
d'une variable, lignes d'un fichier ...
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Communication entre processus : exclusion mutuelle
GNU/Linux Communication
Comm. Inter.
La partage d'une ressource non partageable est réalisé par un mécanisme d'exclusion
mutuelle
Cette technique garanti qu'à tout instant un seul processus utilise la ressource
Les parties de code des processus utilisant la ressource sont appelées section critique Le mécanisme d'exclusion mutuelle garanti qu'à tout instant un seul processus exécute sa section critique
On dit que la section critique est exécutée de
manière atomique
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Communication entre processus : exclusion mutuelle
Processus GNU/Linux Communication
Comm. Inter.
4
Variable partagée i
void main(){
… … … … … … … … }
void main(){
… … … … … … … … }
void main(){
… … … … … … … … }
void main(){
… … … … … … … … } Processus 1
Processus 2 Processus 3
Processus 4
X X
X
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Partage d'une variable sans outil de synchronisation
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Partage de variable
par l'intermédiaire d'un fichier
Un processus père et un processus utilise un entier contenu dans un fichier
Le père initialise l'entier à 1 et l'écrit dans le fichier
Chaque processus fils lit l'entier l'incémente et l'écrit dans le fichier
Si le partage est correcte la valeur écrite doit être : 1, 2, 3, 4, ...
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
GNU/Linux Communication
Comm. Inter.
Tampon = contenu d'un fichier
void main(){
… … Lire
Incrémenter Écrire
… … … }
void main(){
… … …Lire
Incrémenter Écrire
… … }
Processus 1 Processus 2
Tampon de communication
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Algorithme
Père :
Crée le fichier tampon Crée le processus fils
Initialise le contenu du tampon à 1
Boucle dans la lecture, incrémentation, écriture de la variable
Lorsque la variable > max le père arrête le fils par envoi d'un signal SIGTERM
Fils :
Boucle dans la lecture, incrémentation, écriture de la variable
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
GNU/Linux Communication
Comm. Inter.
Programme
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
int main (int narg, char * arg []) { int tampon, fils, variable;
tampon=open("/tmp/tampon",O_RDWR|O_CREAT|
O_TRUNC,S_IRWXU);
if ( tampon < 0) {
perror("Ouverture de /tmp/tampon");
return EXIT_FAILURE;
}
fils=fork();
if ( fils == -1 ){
perror("Echec de la création du fils");
unlink("/tmp/tampon");
return EXIT_FAILURE;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Processus GNU/Linux Communication
Comm. Inter.
Programme
if (fils == 0 ) { while (1){
/* Lecture du tampon */
lseek(tampon, 0, SEEK_SET);
if ( read(tampon,(void *)&variable,4) != 4 ){
perror("Fils erreur de lecture");
return EXIT_FAILURE;
}
fprintf(stderr,"\tFils valeur lue : %d\n",variable);
variable++;
fprintf(stderr,"\tFils valeur écrite : %d\n",variable);
lseek(tampon, 0, SEEK_SET);
if (write(tampon,(void *)&variable,4) == -1){
perror("Fils erreur d'écriture");
return EXIT_FAILURE;
}
if ( variable % 3 == 0 ) sleep(1);
}
return EXIT_SUCCESS;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
GNU/Linux Communication
Comm. Inter.
Programme
/* Processus père */
variable=1;
fprintf(stderr,"Père valeur écrite : %d\n",variable);
lseek(tampon, 0, SEEK_SET);
if (write(tampon,(void *)&variable,4) == -1){
perror("Père erreur d'écriture");
kill(fils, SIGTERM); /* pour tuer le fils */
return EXIT_FAILURE;
}
while( variable < 18 ){
lseek(tampon, 0, SEEK_SET);
if ( read(tampon,(void *)&variable,4) != 4 ){
perror("Père erreur de lecture");
return EXIT_FAILURE;
}
fprintf(stderr,"Père valeur lue : %d\n",variable);
variable++;
fprintf(stderr,"Père valeur écrite : %d\n",variable);
lseek(tampon, 0, SEEK_SET);
if (write(tampon,(void *)&variable,4) == -1){
perror("Père erreur d'écriture");
kill(fils, SIGTERM); /* pour tuer le fils */
return EXIT_FAILURE;
}
if ( variable % 2 == 0) sleep(1);
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Processus GNU/Linux Communication
Comm. Inter.
Programme
/* Terminaison du fils */
kill(fils,SIGTERM);
return EXIT_SUCCESS;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 202
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Processus GNU/Linux Communication
Comm. Inter.
Exclusion mutuelle : verrou fichier
Un processus père et un processus utilise et incrémente chacun à leur tour une variable contenue dans un fichier
Pour garantir un accès à la variable en exclusion mutuelle chaque processus verrouille le fichier tampon en utilisation exclusive à l'aide de la primitive flock
#include <sys/file.h>
int flock(int fd, int operation);
Operation : LOCK_SH : partagé, LOCK_EX :
exclusif, LOCK_UN : supprime le verrou
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
GNU/Linux Communication
Comm. Inter.
Algorithme : Père :
Créer le fichier tampon et initialise la variable à 1
Crée un processus fils Tant que variable < max
Poser le verrou
Lire et incrémenter la variable Écrire la variable
Libérer le verrou
Exclusion mutuelle : verrou fichier
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Processus GNU/Linux Communication
Comm. Inter.
Fils :
Ouvrir le fichier tampon Tant que vrai
Poser le verrou
Lire et incrémenter la variable Écrire la variable
Libérer le verrou
Afin d'obtenir une exécution alternée des
processus chaque processus attends lorsque la variable est multiple de 3 dans le père, 2 dans le fils
Exclusion mutuelle : verrou fichier
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
GNU/Linux Communication
Comm. Inter.
Exclusion mutuelle : verrou fichier
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/file.h>
int main (int narg, char * arg []) { int tampon, variable;
pid_t fils;
tampon=open("/tmp/tampon",O_RDWR|O_CREAT|
O_TRUNC,S_IRWXU);
if ( tampon < 0) {
perror("Ouverture de /tmp/tampon");
return EXIT_FAILURE;
}
variable=1;
lseek(tampon, 0, SEEK_SET);
if (write(tampon,(void *)&variable,4) != 4){
perror("Père erreur d'écriture");
return EXIT_FAILURE;
}
fprintf(stderr,"Père valeur écrite : %d\n",variable);
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Processus GNU/Linux Communication
Comm. Inter.
Exclusion mutuelle : verrou fichier
fils=fork();
if ( fils == -1 ){
perror("Echec de la création du fils");
unlink("/tmp/tampon");
return EXIT_FAILURE;
}
if ( fils == 0 ) {
/* fermeture et ouverture du tampon pour flock */
(void) close(tampon);
tampon=open("/tmp/tampon",O_RDWR);
if ( tampon < 0) {
perror("Ouverture de /tmp/tampon");
return EXIT_FAILURE;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Processus GNU/Linux Communication
Comm. Inter.
Exclusion mutuelle : verrou fichier
while (1){ /* Pose du verrou exclusif */
if ( flock( tampon, LOCK_EX ) < 0) { perror("Fils : échec pose du verrou");
return EXIT_FAILURE;
} /* Lecture du tampon */
lseek(tampon, 0, SEEK_SET);
variable=0;
if ( read(tampon,(void *)&variable,4 ) != 4){
perror("Fils erreur lecture");
return EXIT_FAILURE;
}
fprintf(stderr,"\tFils valeur lue : %d\n",variable);
variable++;
fprintf(stderr,"\tFils valeur écrite : %d\n",variable);
fflush(stderr);
lseek(tampon, 0, SEEK_SET);
if (write(tampon,(void *)&variable,4) != 4 ){
perror("Fils erreur d'écriture");
return EXIT_FAILURE;
} /*Suppression du verrou */
if ( flock( tampon, LOCK_UN ) < 0) {
perror("Fils : echec suppression du verrou");
return EXIT_FAILURE;
}
if ( variable % 3 == 0 ) sleep(1);
}
return EXIT_SUCCESS;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Processus GNU/Linux Communication
Comm. Inter.
/* Processus père */
variable=1;
while( variable < 20 ){
/* Pose du verrou exclusif */
if ( flock( tampon, LOCK_EX ) < 0) {
perror("Père : échec pose du verrou");
return EXIT_FAILURE;
}
variable=0;
lseek(tampon, 0, SEEK_SET);
if ( read(tampon,(void *)&variable,4) != 4){
perror("Père erreur lecture");
return EXIT_FAILURE;
}
fprintf(stderr,"Père valeur lue : %d\n",variable);
variable++;
fprintf(stderr,"Père valeur écrite : %d\n",variable);
fflush(stderr);
lseek(tampon, 0, SEEK_SET);
if (write(tampon,(void *)&variable,4) != 4 ){
perror("Père erreur d'écriture");
return EXIT_FAILURE;
}
/*Suppression du verrou */
if ( flock( tampon, LOCK_UN ) < 0) {
perror("Fils : echec suppression du verrou");
return EXIT_FAILURE;
}
if ( variable % 2 == 0) sleep(1);
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
GNU/Linux Communication
Comm. Inter.
/* Terminaison du fils */
kill(fils,SIGTERM);
(void) wait((int*) NULL);
return EXIT_SUCCESS;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
GNU/Linux Communication
Comm. Inter.
Communication entre processus : synchronisation
L'échange de donnée est souvent réglé par un mécanisme de synchronisation et
l'utilisation d'un tampon de communication Un processus élabore une donnée et la dépose dans un tampon et envoie une information à un second processus pour l'informer de la disponibilité des données Le second processus extrait la donnée du tampon et informe le premier processus que le tampon est vide
L'exécution conditionnelle d'un processus
par un autre est appelé synchronisation
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Processus GNU/Linux Communication
Comm. Inter.
Communication entre processus : synchronisation
void main(){
… … … S1 … … … … }
void main(){
… … … … S2 … … … }
Processus 1 Processus 2
Le processus 2 ne peut aller au delà de S2 tant que le processus 1 n'est pas arrivé en S1
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Le problème du producteur consommateur
Problème classique de communication inter- processus
Un producteur dépose dans un tampon des productions qui sont utilisées par un
processus consommateur Il faut s'assurer que :
Toutes les productions sont consommées dans l'ordre
Aucune n'est dupliquée c'est dire consommée deux fois
Aucune n'est perdue
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Processus GNU/Linux Communication
Comm. Inter.
Le problème du producteur consommateur
Ce problème peut être solutionné de plusieurs manières
Une approche consiste à le considérer comme un double problème de
synchronisation :
S1 : le producteur produit une donnée, la dépose dans le tampon puis synchronise le consommateur
S2 : le consommateur extrait la donnée du
tampon puis synchronise le producteur
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
GNU/Linux Communication
Comm. Inter.
Le problème du producteur consommateur
void main(){
… …
produire() …
… … … }
void main(){
… … … …
consommer() …
… … }
Processus 1 Processus 2
production
Tampon de communication
consomme
produit produire()
… ...
consommer() …
… ...
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Communications entre processus Signaux
Tubes
Tubes nommés
UNIX – GNU/Linux
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Signaux
La primitive :
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
permet d'envoyer le signal sig au processus pid
Contrairement à ce que son nom laisse supposer cette primitive ne termine pas le processus mais envoie un signal à un ou plusieurs processus
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Signaux : droits
Si l'UID effectif du processus émetteur est 0 il peut envoyer un signal à tout processus ( root)
UID réel ou effectif de l'émetteur doit être égal à l'UID effectif de la cible
Dans le cas particulier du signal SIGCONT il suffit que l'émetteur appartienne au même groupe de processus que la cible
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Signaux : fonctionnement
Si pid est > 0 le signal de numéro sig est envoyé au processus de numéro pid : le signal est envoyé par un processus à un autre processus
Si pid = 0 le signal est envoyé à tous les processus du groupe auquel appartient le
processus émetteur : permet par exemple de terminer, en envoyant le signal SIGTERM, tous les processus appartenant à un groupe donné. C'est utilisé par le shell pour terminer tous les processus de la session lorsqu'un utilisateur se déconnecte
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Signaux : fonctionnement
Si pid < -1 le signal est envoyé à tous les processus appartenant au groupe |pid| : permet de terminer (SIGTERM) un démon est tous ses processus fils
Si pid = -1 le signal est envoyé à tous les processus du système sauf le le processus init de numéro 1 : utilisé par exemple lors de l'arrêt du système pour terminer tous les
processus existants
Si sig = 0 rien n'est envoyé cela permet de tester l'existence du processus d'identifiant pid
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Producteur-Consommateur réalisé à l'aide de signaux
Le tampon est matérialisé par le contenu d'un fichier
Chaque processus lit puis écrit à son tour la valeur d'une variable qu'il incrémente de un Chaque processus joue donc alternativement le rôle de producteur et de consommateur
Dans l'exemple les deux processus utilisent un signal pour informer l'autre de la
disponibilité de la donnée
L'échange est réalisé entre un processus père et son fils l'envoi de signal nécessitant de connaître le numéro du destinataire
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Producteur-Consommateur réalisé à l'aide de signaux
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Traitement des signaux
GNU/Linux Communication
Comm. Inter.
#define _GNU_SOURCE /* traitement des signaux BSD */
#define _BSD_SOURCE
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdlib.h>
#include <signal.h>
/* traitement du signal SIGTERM (15) envoyé par le fils au pere */
void sigterm( int s){
fprintf(stderr,"Signal SIGTERM reçu\n");
wait((int*) NULL);
unlink("/tmp/tampon");
exit(EXIT_SUCCESS);
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Traitement des signaux
Processus GNU/Linux Communication
Comm. Inter.
/* traitement du signal SIGUSR1 (10) envoyé par le fils au père */
void sigusr1( int s){
fprintf(stderr,"Père signal %d reçu\n",s);
return;
}
/* traitement du signal SIGUSR2 (12) envoyé par le père au fils */
void sigusr2( int s){
fprintf(stderr,"Fils signal %d reçu\n",s);
return;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Ouverture du fichier et création du processus fils
GNU/Linux Communication
Comm. Inter.
int main (int narg, char * arg []) { int tampon, fils, variable;
tampon=open("/tmp/tampon",O_RDWR|O_CREAT|O_TRUNC,S_IRWXU);
if ( tampon < 0) {
perror("Ouverture de /tmp/tampon");
return EXIT_FAILURE;
}
switch ( fils=fork() ){
case -1 :
perror("Echec de la création du fils");
unlink("/tmp/tampon");
return EXIT_FAILURE;
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Processus fils
Processus GNU/Linux Communication
Comm. Inter.
case 0 :
if ( signal(SIGUSR2, sigusr2) == SIG_ERR ){
perror("Traistement de SIGUSR2 par le fils");
kill(getppid(), SIGTERM); /* pour avertir le père */
return EXIT_FAILURE;
}
while (1){ /* Attente du signal SIGUSR2 pour lire */
pause();
lseek(tampon, 0, SEEK_SET);
read(tampon,(void *)&variable,4);
fprintf(stderr,"Fils valeur lue : %d\n",variable);
variable++;
fprintf(stderr,"Fils valeur écrite : %d\n",variable);
lseek(tampon, 0, SEEK_SET);
if (write(tampon,(void *)&variable,4) == -1){
perror("Fils erreur d'écriture");
kill(getppid(), SIGTERM); /* pour avertir le père */
return EXIT_FAILURE;
}
kill(getppid(), SIGUSR1);
}
return EXIT_SUCCESS;
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Mise en place du traitement du signal dans le père
GNU/Linux Communication
Comm. Inter.
/* Processus père */
if ( signal(SIGUSR1, sigusr1) == SIG_ERR ){
perror("Traistement de SIGUSR1 par le père");
kill(fils, SIGTERM); /* pour terminer le fils */
/* autoterminaison */
kill(getpid(),SIGTERM);
return EXIT_FAILURE;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Producteur-Consommateur réalisé à l'aide de signaux
Processus GNU/Linux Communication
Comm. Inter.
sleep(1); /* pour que le fils s'exécute en premier */
variable=1;
while( variable != 11 ){
fprintf(stderr,"Père valeur écrite : %d\n",variable);
lseek(tampon, 0, SEEK_SET);
if (write(tampon,(void *)&variable,4) == -1){
perror("Fils erreur d'écriture");
kill(fils, SIGTERM);
return EXIT_FAILURE;
}
kill(fils, SIGUSR2);
pause(); /* Attente du signal SIGUSR1 pour lire */
lseek(tampon, 0, SEEK_SET);
read(tampon,(void *)&variable,4);
fprintf(stderr,"Père valeur lue : %d\n",variable);
variable++;
}
/* Terminaison du fils */
kill(fils,SIGTERM);
/* autoterminaison */
kill(getpid(),SIGTERM);
return EXIT_SUCCESS;
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
GNU/Linux Communication
Comm. Inter.
Exécution
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Remarques
Le sleep(1) dans le processus père après création du fils garanti que le processus fils va s'exécuter en premier et mettre en place le traitement du signal SIGUSR2 avant que le père n'émette le premier signal
Cette double synchronisation du processus père par le fils et inversement peut être
réalisée sans problème avec deux processus indépendants il suffit de commencer chaque processus par une lecture sur l'entrée
standard, du numéro de processus de l'autre
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Communications entre processus Signaux
Tubes
Tubes nommés
UNIX – GNU/Linux
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Tube
Un tube est une structure de communication créée et gérée par la système en mémoire C'est un outil de communication car il est
possible d'en lire le contenu et d'y écrire des données
De synchronisation :
Le SE garanti que toute opération d'une taille inférieure à PIPE_BUFF, défini dans limits.h, est réalisée de manière atomique
Les données sont lues dans l'ordre ou elle ont été écrites
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Tube
La lecture d'un tube vide est
bloquante si il existe un écrivain au moins du tube = un processus dans lequel le descripteur d'écriture est valide
L'écriture d'un tube plein est
bloquante si il existe un lecteur au moins du tube = un processus dans lequel le descripteur de lecture est valide
L'écriture d'un tube sans lecteur déclenche le signal SIGPIPE qui par défaut arrête le
processus
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Tube : création
Primitive :
#include <unistd.h>
int pipe(int pipefd[2]);
Crée et ouvre un tube dont les descripteurs de bas niveau sont :
pipefd[0] en lecture pipefd[1] en écriture Retourne :
= 0 en cas de réussite
< 0 en cas d'échec
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Tube : création
Un tube ne peut être ouvert, la primitive pipe crée et ouvre le tube
Après fermeture le tube devient inaccessible Pour l'utiliser à haut niveau il faut utiliser
fdopen
Les descripteurs étant transmis dans
l'héritage durant fork l'utilisation d'un tube entre deux processus implique que le tube ait été créé par un ancêtre commun
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Exemple : tube de communication entre deux processus
Les tubes de communication permettent à deux processus de communiquer
Une utilisation classique consiste à rediriger : la sortie standard du premier dans le tube
L'entrée standard du second depuis le tube
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
GNU/Linux Communication
Comm. Inter.
ls -l -a répertoire | wc
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
ls -l -a répertoire | wc
Ce programme C est équivalent à la commande ls -l -a | wc
Le programme comporte deux processus Le père exécute la commande wc
Le fils la commande ls -l -a répertoire
A la terminaison du fils le processus père recevra EOF comme résultat de lecture ce qui rend inutile l'attente de la fin du fils
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
GNU/Linux Communication
Comm. Inter.
ls -l -a répertoire | wc : création du tube
#include <unistd.h>
#include <stdlib.h>
#include<stdio.h>
int main(int narg, char ** argv){
pid_t fils;
int tube[2];
/* Verification de l'existence d'un paramètre au moins */
if ( narg < 2 ){
fprintf(stderr,"Il faut un paramètre au moins : le répertoire\n");
return EXIT_FAILURE;
}
if ( pipe(tube) != 0) {
perror("Création du tube");
return EXIT_FAILURE;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Processus GNU/Linux Communication
Comm. Inter.
ls -l -a répertoire | wc : processus fils
/* creation du fils 1 executant ls -l -a*/
fils=fork();
switch ( fils ) { case -1 :
perror("Pere : echec du fork");
return 1;
case 0 :
close (tube[0]); /*lecture tube jamais utilise */
close (1); /* redirection de stdout */
dup (tube[1]);
/* fermeture de descripteurs non utilises devenus inutiles */
close (tube[1]);
/* on peut maintenant lancer l'execution de ls -l */
fprintf(stderr,"On lance ls -l -a %s\n",*(argv+1));
execlp("ls","ls","-l", "-a", *(argv+1), (char*)NULL);
perror("Echec de l'execution du programme ls");
return EXIT_FAILURE;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
GNU/Linux Communication
Comm. Inter.
ls -l -a répertoire | wc : processus père
/* Processus pere on peut maintenant lancer l'execution de wc -l */
close (tube[1]); /* jamais utilise */
close (0); /* redirection de stdin */
dup (tube[0]);
/* fermeture de descripteurs non utilises devenus inutiles */
close (tube[0]);
execlp("wc","wc",(char*)NULL);
perror("Echec de l'execution de wc");
return EXIT_FAILURE;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Producteur-Consommateur réalisé à l'aide de tubes
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Producteur-Consommateur réalisé à l'aide de tubes
Les processus échangeant des informations dans les deux sens il est nécessaire d'utiliser 2 tubes
Le premier père_fils permet l'échange dans le sens père → fils
Le second fils_père dans le sens fils → père Le processus père termine l'exécution
lorsque la valeur lue est 10, il ferme alors le descripteur en écriture du tube père_fils
Le fils lisant un tube vide sans écrivain reçoit 0 et se termine
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Initialisation
Processus GNU/Linux Communication
Comm. Inter.
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int main (int narg, char * arg []) {
int pere_fils[2], fils_pere[2], fils, variable, n;
if (pipe(pere_fils)){ /* création des tubes */
perror("Création du premier tube");
return EXIT_FAILURE;
}
if (pipe(fils_pere)){
perror("Création du second tube");
return EXIT_FAILURE;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Processus fils
GNU/Linux Communication
Comm. Inter.
switch ( fils=fork() ){
case -1 :
perror("Echec de la création du fils");
return EXIT_FAILURE;
case 0 :
/* fermeture des descripteurs */
close(pere_fils[1]); close(fils_pere[0]);
while (1){
n=read(pere_fils[0],(void *)&variable,4);
if ( n == 0 ) {
close(fils_pere[1]);close(pere_fils[0]);
return EXIT_SUCCESS;
}
fprintf(stderr,"Fils valeur lue : %d\n",variable);
variable++;
if (write(fils_pere[1],(void *)&variable,4) == -1){
perror("Fils erreur d'écriture");
return EXIT_FAILURE;
}
fprintf(stderr,"Fils valeur écrite : %d\n",variable);
}
return EXIT_SUCCESS;
} /* Fin switch */
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Processus père
Processus GNU/Linux Communication
Comm. Inter.
/* Processus père */
close(pere_fils[0]); close(fils_pere[1]);
variable=1;
while( variable != 11 ){
if (write(pere_fils[1],(void *)&variable,4) == -1){
perror("Fils erreur d'écriture");
return EXIT_FAILURE;
}
fprintf(stderr,"Père valeur écrite : %d\n",variable);
read(fils_pere[0],(void *)&variable,4);
fprintf(stderr,"Père valeur lue : %d\n",variable);
variable++;
}
close(pere_fils[1]);
wait((int*)NULL);
return EXIT_SUCCESS;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Exécution
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Communications entre processus Signaux
Tubes
Tubes nommés
UNIX – GNU/Linux
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Tube nommé
Les tubes ne peuvent être utilisés entre deux processus que si le tube a été créé dans un ancêtre commun
Les tubes nommés étant des éléments du système de fichier ils peuvent être utilisés entre 2 processus quelconque
La primitive mknod ou la fonction de
bibliothèque mkfifo permettent de créer le tube
Chaque processus désirant utiliser le tube doit l'ouvrir à l'aide de la primitive open, conseillé, ou avec fopen
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Tube nommé
Processus GNU/Linux Communication
Comm. Inter.
L'ouverture d'un tube en lecture est
bloquante jusqu'à l'ouverture du tube en écriture
L'ouverture d'un tube en écriture est
bloquante jusqu'à l'ouverture du tube en lecture
Le tube nommé est un outil de
synchronisation et de communication si les
opérations effectuées sont d'une longueur
inférieure PIPE_BUF
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Client-serveur utilisant un tube nommé
GNU/Linux Communication
Comm. Inter.
Exemple similaire au principe de
communication utilisé entre le serveur X et ses différents clients les fenêtres graphiques Le serveur créé un tube et y lit les requêtes des clients : une commande à exécuter
La commande est exécutée en utilisant la fonction de bibliothèque system qui évite l'analyse de la commande pour en trouver les paramètres
system créé un processus fils pour exécuter
la commande
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Serveur : créateur et lecteur du tube
Processus GNU/Linux Communication
Comm. Inter.
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <stdio.h>
int main (int narg, char * arg []) { int d;
FILE * fifo;
char commande[256];
/* creation du tube nomme */
if ( mkfifo("/tmp/commande",0700) < 0 ){
if ( errno != EEXIST ) {
perror("Création du tube nommé");
return EXIT_FAILURE;
} else
fprintf(stderr,"Le tube nommé existe il n'est pas créé\n");
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Serveur : créateur et lecteur du tube
GNU/Linux Communication
Comm. Inter.
/* ouverture du tube en lecture */
if ( (d = open("/tmp/commande",O_RDONLY)) < 0 ){
perror("Echec de l'ouverture du tube nommé avec open");
unlink("/tmp/commande");
return EXIT_FAILURE;
}
if ( (fifo = fdopen(d, "r")) == NULL ){
perror("Echec de l'ouverture du tube nommé avec fopen");
close(d);
unlink("/tmp/commande");
return EXIT_FAILURE;
}
while(1) {
/* lecture de la commande à exécuter */
if ( fgets(commande, 256, fifo) == commande ){
fprintf(stderr,"Exécution de commande -%s-",commande);
system(commande);
} }
return EXIT_SUCCESS;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Client : écrivain du tube
Processus GNU/Linux Communication
Comm. Inter.
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
int main (int narg, char * arg []) { int d;
FILE * fifo;
char commande[256];
/* ouverture du tube en lecture */
if ( (d = open("/tmp/commande",O_WRONLY)) < 0 ){
perror("Echec de l'ouverture du tube nommé avec open");
return EXIT_FAILURE;
}
if ( (fifo = fdopen(d,"w")) == NULL){
perror("Echec de l'ouverture du tube nommé avec fopen");
return EXIT_FAILURE;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Client : écrivain du tube
GNU/Linux Communication
Comm. Inter.
*commande='\0';
while(1) {
/* lecture de la commande à exécuter */
fprintf(stdout,"Commande à exécuter : ");
if ( fgets(commande, 256, stdin) != NULL) { if (strlen(commande) != 1){
/* la commande n'est pas vide */
if (fputs(commande, fifo) != EOF ) { fprintf(stderr,"flush fifo\n");
fflush(fifo);
}
else {
fprintf(stderr,"Le tube nommé à été fermé\n");
break;
} } else
break;
} }
fclose(fifo);
return EXIT_SUCCESS;
}
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Processus GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
JLA 2015, AG 2021JLA 2015, AG 2021
Client : écrivain du tube
GNU/Linux Communication
Comm. Inter.
IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr
A 2015, AG 2021JLA 2015, AG 2021
Serveur : lecteur du tube
Processus GNU/Linux Communication
Comm. Inter.