• Aucun résultat trouvé

Processus et gestion de processus

N/A
N/A
Protected

Academic year: 2022

Partager "Processus et gestion de processus"

Copied!
71
0
0

Texte intégral

(1)

A 2015, AG 2021JLA 2015, AG 2021

Processus et gestion de processus

Processus GNU/Linux Communication

Comm. Inter.

(2)

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.

(3)

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.

(4)

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

(5)

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

(6)

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.

(7)

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.

(8)

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

(9)

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.

(10)

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;

}

(11)

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;

}

(12)

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);

}

(13)

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;

}

(14)

IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr

JLA 2015, AG 2021JLA 2015, AG 202

(15)

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

(16)

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

(17)

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

(18)

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);

(19)

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;

}

(20)

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;

}

(21)

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);

}

(22)

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;

}

(23)

IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr

A 2015, AG 2021JLA 2015, AG 2021

Processus GNU/Linux Communication

Comm. Inter.

(24)

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

(25)

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

(26)

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.

(27)

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

(28)

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() …

… ...

(29)

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.

(30)

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.

(31)

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.

(32)

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.

(33)

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.

(34)

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.

(35)

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.

(36)

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);

}

(37)

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;

}

(38)

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;

(39)

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;

(40)

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;

}

(41)

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;

(42)

IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr

JLA 2015, AG 2021JLA 2015, AG 2021

GNU/Linux Communication

Comm. Inter.

Exécution

(43)

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.

(44)

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.

(45)

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.

(46)

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.

(47)

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.

(48)

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.

(49)

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.

(50)

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

(51)

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.

(52)

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;

}

(53)

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;

}

(54)

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;

}

(55)

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.

(56)

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.

(57)

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;

}

(58)

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 */

(59)

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;

}

(60)

IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr

JLA 2015, AG 2021JLA 2015, AG 2021

Exécution

GNU/Linux Communication

Comm. Inter.

(61)

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.

(62)

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.

(63)

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

(64)

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

(65)

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");

}

(66)

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;

}

(67)

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;

}

(68)

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;

}

(69)

IUT BM J.-L. Anthoine, Arnaud.Giersch@univ-fcomte.fr

A 2015, AG 2021JLA 2015, AG 2021

Processus GNU/Linux Communication

Comm. Inter.

(70)

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.

(71)

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.

Références

Documents relatifs

Exemple : Asservissement num érique de la vitesse d é rique de la vitesse d’ ’un moteur un moteur. Cas de la commande d’un moteur CC par

Interblocage (deadlock) : aucun processus suspendu en dehors d’une section critique ne doit bloquer les autres pour y entrer. Aucune hypothèse ne doit être faite sur les

Interblocage (deadlock) : aucun processus suspendu en dehors d’une section critique ne doit bloquer les autres pour y entrer. Aucune hypothèse ne doit être faite sur les

CON 01 GERER LES ACQUISITIONS DE SOLUTIONS CON 02 GERER LE DEVELOPPEMENT DE SOLUTIONS CON 03 GERER LE CATALOGUE DE SERVICES CON 04 GERER LES NIVEAUX DE SERVICE CON 05 GERER

Il s’agit surtout de commandes assez générales, dont tout administrateur aura besoin un jour ou l’autre.. Les commandes pour l’utilisateur courant se trouvent

• Tout processus connaissant la référence d’un tube nommé peut l’ouvrir avec la primitive « open ».. • Les fichiers correspondants à des tubes sont identifiés

événement extérieur ou s'être mis en attente), le système d'exploitation va le faire passer dans l'état prêt et activer un autre processus de la liste des processus éligibles..

fork() rend la valeur 0 dans le processus fils, et le numéro d’identification (PID) du fils créé dans le processus père ; on récupère donc cette valeur par une instruction du type