Vous êtes sur la page 1sur 21

Les processus et les pipes en C

MEUTER Cdric / LEVY Eythan

Les processus et les pipes en C p.1/21

Cration de processus (I)


La cration de processus se fait laide du system call fork() :
#include <sys/types.h> #include <unistd.h> pid_t fork();

Cest la seule fonction C qui retourne deux fois ! Au moment de lappel du fork, le processus courant est clon intgralement Lexecution reprend des deux cots partir de lendroit o le fork t appel et lappel fork() renvoie des valeurs diffrentes au deux processus : Le clone (le processus ls) reoit la valeur 0 Loriginal (le processus pre) reoit le PID du processus ls

Les processus et les pipes en C p.2/21

Exercice (I)
Ecrivez un programme C qui cre un processus ls. Les deux processus devront ensuite afcher lcran un message indiquant quel processus ils sont (pre ou ls).

Les processus et les pipes en C p.3/21

Correction (I)
#include #include #include #include <stdio.h> <stdlib.h> <unistd.h> <sys/types.h>

int main(int argc, char *argv[]) { pid_t pid = fork(); if (pid == 0) // processus fils printf("Processus fils (PID = %d, PID du pre = %d)\n", getpid(), getppid()); else if (pid != -1) // processus pre printf("Processus pre (PID = %d, PID du fils = %d)\n", getpid(), pid); else { perror("Erreur durant le fork"); return EXIT_FAILURE; } return EXIT_SUCCESS; }

Les processus et les pipes en C p.4/21

Correction (II)
Exemple dexcution :
[cmeuter@litpc34 source]$ gcc -Wall fork.c -o fork [cmeuter@litpc34 source]$ ./fork Processus fils (PID = 5974, PID du pre = 5973) Processus pre (PID = 5973, PID du fils = 5974)

Nous avons utilis deux system calls supplmentaires dans cet exercice :
#include <sys/types.h> #include <unistd.h> pid_t getpid(void); pid_t getppid(void);

getpid permet dobtenir le PID dun processus et getppid (parent PID) permet, quant lui, dobtenir le PID du pre dun processus.

Les processus et les pipes en C p.5/21

Execution dun programme (I)


A partir dun programme C, on peut lancer un autre programme en lui passant des paramtres (comme le shell le fait partir dune ligne de commande). Lexcution dun programme se fait laide de la famille de system calls exec Lorsquun processus fait appel exec, le processus appelant est remplace par le programme pass en paramtre. Si cela fonctionne, lappel exec ne retourne pas !

Les processus et les pipes en C p.6/21

Execution dun programme (II)


Pourquoi une famille de systme calls ? Il existe en fait plusieures variantes de exec :
int int int int execl(const char *program, const char *arg, ...); execlp(const char *program, const char *arg, ...); execv(const char *program, const char *argv[]); execvp(const char *program, const char *argv[]);

Les versions avec un l passe les paramtres du programme en utilisant une liste darguments termine par NULL.
execl("/bin/ls", "/bin/ls", "-l", "-a", NULL);

Les versions avec un p cherche le programme dans la variable denvironnement PATH. Les versions sans p requiert donc un chemin absolu (partant du /).
execlp("ls", "ls", "-l", "-a", NULL);

Les processus et les pipes en C p.7/21

Execution dun programme (III)


Les versions avec v passe les paramtres du programme en utilisant un vecteur darguments termin par NULL.
char *arguments[4]; arguments[0] arguments[1] arguments[2] arguments[3] = = = = "/bin/ls"; "-l"; "-a"; NULL;

execv("/bin/ls", arguments);

Les processus et les pipes en C p.8/21

Attente de processus (I)


Il est parfois ncessaire pour le processus pre dattendre la n du processus ls avant de continuer son traitement (attente du rsultat). Pour cela, on peut utiliser les system calls wait et waitpid.
#include <sys/types.h> #include <sys/wait.h> pid_t wait(int *status); pid_t waitpid(pid_t pid, int *status, int options);

Le system call wait attent la n dun des processus ls, retourne son PID et stocke (entre autre) dans lentier point par status (si status est diffrent de NULL), le code de retour du processus ls (ce qui est renvoy par la fonction main du processus ls).

Les processus et les pipes en C p.9/21

Attente de processus (II)


La system call waitpid est trs similaire wait. Dans ce cas, le processus pre attent la n du processus ls dont le PID est prcis en paramtre (dans le cas o plusieurs ls ont t crs). Le paramtre entier option permet (entre autre) de rentre lappel waitpid non bloquant avec la constante WNOHANG. Si cela nest pas ncessaire, on utilise la valeur 0. Pour extraire le code de retour du processus ls de status, il faut dabord tester que le processus cest bien termin correctement. Pour cela, on utilise la macro WIFEXITED(status), qui renvoie vrai si le processus ls cest termin normalement. Ensuite pour obtenir sont code de retour, on utilise la macro WEXITSTATUS(status).

Les processus et les pipes en C p.10/21

Exercice (II)
Ecrivez un programme launch qui excute une commande passe via les arguments du programme dans un processus ls, qui attend sa valeur de retour et qui lafche lcran. Par exemple, ./launch ps -f devra excuter la commande ps -f et afcher sa valeur de retour.

Les processus et les pipes en C p.11/21

Correction (III)
Squelette du programme :
#include #include #include #include #include <stdio.h> <stdlib.h> <unistd.h> <sys/wait.h> <sys/types.h>

int main(int argc, char *argv[]) { pid_t pid; int status, i; char **argument; pid = fork(); if (pid == 0) { /* processus fils */ } else if (pid != -1) { /* processus pre */ } else { perror("Erreur durant le fork"); return EXIT_FAILURE; } return EXIT_SUCCESS; }

Les processus et les pipes en C p.12/21

Correction (IV)
Programme du ls :
argument = (char **)malloc(argc * sizeof(char *)); for (i = 0; i < argc - 1; ++i) argument[i] = argv[i + 1]; argument[argc-1] = NULL; if (execvp(argv[1], argument) == -1) { perror("Erreur durant lexec"); return EXIT_FAILURE; }

Programme du pre :
printf("En attente du fils\n"); wait(&status); if (WIFEXITED(status)) printf("Le code de retour du fils est %d\n", WEXITSTATUS(status)); else printf("Le processus fils ne sest pas termin correctment\n");

Les processus et les pipes en C p.13/21

Correction (V)
Exemples dexcutions :

[cmeuter@litpc34 source]$ ./launch ./launch ps -f En attente du fils En attente du fils UID PID PPID C STIME TTY TIME CMD cmeuter 2954 2953 0 11:06 pts1 00:00:00 /bin/bash cmeuter 9620 2954 0 17:25 pts1 00:00:00 ./launch ./launch ps cmeuter 9621 9620 0 17:25 pts1 00:00:00 ./launch ps -f cmeuter 9622 9621 0 17:25 pts1 00:00:00 ps -f Le code de retour du fils est 0 Le code de retour du fils est 0

[cmeuter@litpc34 source]$ ./launch ./failure En attente du fils Le code de retour du fils est 1

Les processus et les pipes en C p.14/21

Les pipes
Les pipes permettent deux processus tournant sur la mme machine de communiquer entre eux. Ils fonctionnent comme des tuyaux (pipes en anglais) unidirectionels entre deux processus. Il existe deux type de pipes : Les pipes anonymes utiliss pour la communication entre parent (le pre avec un ls, un ls avec un autre ls). Les pipes nomms utiliss pour la communication entre deux processus indpendants (pas de lien de parent direct entre les deux)

Les processus et les pipes en C p.15/21

Les pipes anonymes


Le cration de pipes anonymes se fait laide du system call pipe.
#include <unistd.h> int pipe(int fd[2]);

Lappel pipe cre une paire de le descriptors stocke dans fd. fd[0] sert la lecture du pipe et fd[1] sert lcriture dans le pipe. Pour tablir une communication (unidirectionelle !) laide dun pipe, il faut que le processus pre cre un pipe avant de faire un (ou plusieurs) appel(s) fork. Ds lors, aprs le fork, le processus pre et le(s) processus ls peuvent accder aux pipe en utilisant fd. Pour une communication bidirectionelle, il faut crer deux pipes.

Les processus et les pipes en C p.16/21

Les pipes nomms


Le cration de pipe nomm se fait laide du system call mkfifo.
#include <sys/types.h> #include <sys/stat.h> int mkfifo(const char *pathname, mode_t mode);

Une fois cr, le pipe nomm apparatra comme un chier spcial dans le systme de chier, lendroit indiqu par pathname. Le paramtre mode quant lui, permet de donner les permissions (lecture, criture, ...) ce chier spcial (pour plus de dtails sur les constantes utilisables pour mode, consultez les man pages de open(2)).

Les processus et les pipes en C p.17/21

Exercice (III)
Ecrivez un programme qui cre un processus ls. Le processus pre demandera ensuite deux nombres entiers lutilisateur qui seront transmis via un pipe au processus ls, qui en calculera la somme. Cette somme sera renvoye au processus pre via un (autre) pipe.

Les processus et les pipes en C p.18/21

Correction (VI)
Squelette du programme :
#include #include #include #include <sys/types.h> <stdio.h> <stdlib.h> <unistd.h>

int main(int argc, char **argv) { pid_t pid; int pere_fils[2], fils_pere[2], nbr1, nbr2, somme; if (pipe(pere_fils) == -1 || pipe(fils_pere) == -1) { perror("Erreur la creation des pipes"); return EXIT_FAILURE; } pid = fork(); if (pid == 0) { /* processus fils */ } else if (pid != -1) { /* processus pre */ } else { perror("Erreur durant le fork"); return EXIT_FAILURE; } return EXIT_SUCCESS; }

Les processus et les pipes en C p.19/21

Correction (VII)
Programme du ls :
close(pere_fils[1]); close(fils_pere[0]); read(pere_fils[0], (void *)(&nbr1), sizeof(int)); read(pere_fils[0], (void *)(&nbr2), sizeof(int)); somme = nbr1 + nbr2; write(fils_pere[1], (void *)(&somme), sizeof(int));

Les processus et les pipes en C p.20/21

Correction (VII)
Programme du pre :
close(fils_pere[1]); close(pere_fils[0]); printf("Introduisez deux nombre : "); scanf("%d", &nbr1); scanf("%d", &nbr2); write(pere_fils[1], (void *)(&nbr1), sizeof(int)); write(pere_fils[1], (void *)(&nbr2), sizeof(int)); read(fils_pere[0], (void *)(&somme), sizeof(int)); printf("La somme des deux nombres est %d\n", somme);

Les processus et les pipes en C p.21/21