#include <memoire.h>La compilation du module memoire.c peut être effectuée en utilisant la commande :
sh> cc -D_XOPEN_SOURCE -c memoire.cLa compilation et l'édition de liens d'un programme désirant utiliser la fonction peut être effectuée de la façon suivante :
sh> cc -o prog prog.c memoire.o
pere: proc_num=7678 premier= 0 deuxieme=7678 fils: proc_num= 0 premier= 0 deuxieme=7678 fils: proc_num= 0 premier= -12 deuxieme= -15 pere: proc_num=7679 premier= -12 deuxieme=7678Il faut d'abord remarquer que la variable premier pointe sur un segment de mémoire partagée (ce qui n'est le cas ni de proc_num ni de deuxieme).
La première ligne est générée par le processus initial après l'affectation de proc_num à la valeur de getpid() (ici 7678), du pid_t partagé à 0 et de deuxième à l'adresse de la variable non partagée un_entier laquelle est elle-même initialisée à la valeur de proc_num (soit 7678).
Après le fork() et quelque soit la politique d'ordonnancement utilisée c'est le fils qui réalisera son calcul car le père est bloqué sur wait(NULL) qui permet d'attendre la mort d'un de ses fils (mais comme il n'en a qu'un).
La deuxième ligne est générée par le processus fils lequel a hérité d'une copie de l'espace d'adressage de son père. Mais sa variable proc_num est modifiée au retour du fork() (valeur 0).
La troisième ligne est générée par le processu fils après modification du segment de mémoire partagée (valeur -12) et de la variable pointée par deuxieme (valeur -15).
La quatrième ligne est générée par le processus père après que son unique fils ait terminé son calcul. La variable proc_num a pris la valeur du pid du fils lors du retour du fork(). Le segment partagé a été modifié par le fils (valeur -12) quant à la variable pointée par deuxieme aucune modification ne lui a été apportée depuis le fork().
cas 1 | cas 2 | cas 3 |
pere(1) | pere(1) | pere(1) |
pere(2) | fils(1) | fils(1) |
fils(1) | pere(2) | fils(2) |
fils(2) | fils(2) | pere(2) |
De plus la variable partagée aura (dans le père) deux valeurs possibles : 0 si le père génère son message avant que le fils ne touche au segment (cas 1 et cas 2), -12 sinon (cas 2 et cas 3).
Si le père meure avant le fils celui-ci se retrouvera orphelin (et sera donc adopté par un autre processus). Dans le cas contraire le fils restera dans l'état zombi jusqu'à la mort du père.
cas a | cas b | cas c | cas d |
pere | fils | pere | fils |
fils | fils | pere | pere |
Il faut remarquer que la valeur du fork() est stockée dans un segment de mémoire partagé. Selon la politique d'ordonnancement il est possible que :
Donc si le fils est interrompu par l'ordonnanceur pendant la délivrance de SIGUSR1 et que le père est choisi, il est possible que ce dernier puisse envoyer plusieurs fois SIGUSR1 avant que l'ordonnanceur ne redonne la main au fils. Auquel cas, le fils aura perdu quelques signaux au passage.
Plus la boucle for (i=0; ...) est longue plus nombreux seront les signaux perdus.
Les redirections effectuées sont :
Une remarque à faire sur la redirection du fichier /etc/passwd. Si l'on effectue la commande suivante :
sh> ( cat truc ; cat muche ) > biduleLe résultat produit est celui naturellement attendu, c'est-à-dire concaténation des deux fichiers truc puis muche dans bidule. Et cela fonctionne car les deux commandes cat et cut partagent le même fichier ouvert (bidule en écriture). Donc lorsque la première commande cat termine la position courante du fichier (propriété du fichier ouvert) est réutilisée par la deuxième commande cat.
Pour notre commande c'est bien la mème chose qui se produit mais en entrée. Donc lorsque la commande cut a terminé de lire le fichier /etc/passwd la position courante du fichier ouvert en lecture est celle de la fin de fichier. Ainsi la commande cat tente de lire alors que le fichier ouvert est déjà en fin de fichier. Donc cat ne produit rien !
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <unistd.h> #define REDIRECT(from,to) { close(to); dup(from); close(from); } main() { int etc, res, p[2], i, pid; if (fork()==0) { etc = open("/etc/passwd",O_RDONLY); REDIRECT(etc,0); pipe(p); if (fork()==0) { close(p[1]); res = open("res",O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR); REDIRECT(res,1); REDIRECT(p[0],0); execlp("cat","cat",NULL); } if (fork()==0) { char c; close(p[0]); REDIRECT(p[1],1); execlp("cut","cut","-f1","-d:",NULL); } close(p[0]); close(p[1]); wait(NULL); wait(NULL); exit(EXIT_SUCCESS); } wait(NULL); }
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> int lit_ligne(char *ligne,int fic) { int i=0; char c; while (read(fic,&c,1)>0) { ligne[i++] = c; if (c=='\n') { ligne[i++] = '\0'; return 1; } } return 0; } int main(int argc,char *argv[]) { pid_t pid; int sig, tube, base; char *nom_tube, a_chercher, ligne[256]; pid = atoi(argv[1]); sig = atoi(argv[2]); nom_tube = argv[3]; a_chercher = argv[4][0]; base = open("/tmp/base_de_donnees",O_RDONLY); tube = open(nom_tube,O_WRONLY); while (lit_ligne(ligne,base)) { if (ligne[0]==a_chercher) { write(tube,ligne,256); kill(pid,sig); } } ligne[0]='\0'; write(tube,ligne,256); kill(pid,sig); close(base); close(tube); exit(EXIT_SUCCESS); }
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> int main(int argc,char *argv[]) { int tube_serveur, sig, i; pid_t pid; char nom_tube[256], c; mkfifo("/tmp/tube",S_IRUSR|S_IWUSR); tube_serveur = open("/tmp/tube",O_RDONLY); while (1) { if (read(tube_serveur,&pid,sizeof(pid_t))==0) { close(tube_serveur); tube_serveur = open("/tmp/tube",O_RDONLY); continue; } read(tube_serveur,&sig,sizeof(int)); i = 0; while (read(tube_serveur,&c,1)>0) { nom_tube[i++] = c; if (c=='\0') break; } read(tube_serveur,&c,1); if (fork()==0) { char pids[10], sigs[10], cs[2]; sprintf(pids,"%d",pid); sprintf(sigs,"%d",sig); sprintf(cs,"%c",c); execlp("service","service",pids,sigs,nom_tube,cs,NULL); } } }
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> int tube_reponse; char nom_tube[256]; int lit_ligne(char *ligne,int fic) { int i=0; char c; if (read(fic,ligne,256)>0) return 1; return 0; } void capture(int sig) { char ligne[256]; while (lit_ligne(ligne,tube_reponse)) { if (ligne[0]=='\0') { close(tube_reponse); unlink(nom_tube); exit(EXIT_SUCCESS); } printf("J'ai lu : %s",ligne); } } int main(int argc,char *argv[]) { pid_t pid; int signal; int tube_serveur; struct sigaction act; sigset_t ens; sigemptyset(&ens); act.sa_handler = capture; act.sa_mask = ens; act.sa_flags = 0; sigaction(SIGUSR1,&act,NULL); pid = getpid(); signal = SIGUSR1; sprintf(nom_tube,"/tmp/tube_client_%d",pid); mkfifo(nom_tube,S_IRUSR|S_IWUSR); tube_reponse = open(nom_tube,O_RDONLY|O_NONBLOCK); tube_serveur = open("/tmp/tube",O_WRONLY); write(tube_serveur,&pid,sizeof(pid_t)); write(tube_serveur,&signal,sizeof(int)); write(tube_serveur,nom_tube,strlen(nom_tube)+1); write(tube_serveur,argv[1],1); close(tube_serveur); while (1) pause(); }
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdlib.h> #include <signal.h> int tube_reponse[2], ferme; char nom_tube[2][256]; int lit_ligne(char *ligne,int fic) { int i=0; char c; if (read(fic,ligne,256)>0) return 1; return 0; } void capture(int sig) { char ligne[256]; int tube; tube = sig==SIGUSR1?tube_reponse[0]:tube_reponse[1]; while (lit_ligne(ligne,tube)) { if (ligne[0]=='\0') { close(tube); unlink(nom_tube[sig==SIGUSR1?0:1]); ferme++; return; } printf("J'ai lu : %s",ligne); } } int main(int argc,char *argv[]) { pid_t pid; int signal; int tube_serveur; struct sigaction act; sigset_t ens; ferme = 0; sigemptyset(&ens); sigaddset(&ens,SIGUSR2); act.sa_handler = capture; act.sa_mask = ens; act.sa_flags = 0; sigaction(SIGUSR1,&act,NULL); sigemptyset(&ens); sigaddset(&ens,SIGUSR1); act.sa_mask = ens; sigaction(SIGUSR2,&act,NULL); pid = getpid(); sprintf(nom_tube[0],"/tmp/tube1_client_%d",pid); mkfifo(nom_tube[0],S_IRUSR|S_IWUSR); tube_reponse[0] = open(nom_tube[0],O_RDONLY|O_NONBLOCK); sprintf(nom_tube[1],"/tmp/tube2_client_%d",pid); mkfifo(nom_tube[1],S_IRUSR|S_IWUSR); tube_reponse[1] = open(nom_tube[1],O_RDONLY|O_NONBLOCK); tube_serveur = open("/tmp/tube",O_WRONLY); write(tube_serveur,&pid,sizeof(pid_t)); signal = SIGUSR1; write(tube_serveur,&signal,sizeof(int)); write(tube_serveur,nom_tube[0],strlen(nom_tube[0])+1); write(tube_serveur,argv[1],1); write(tube_serveur,&pid,sizeof(pid_t)); signal = SIGUSR2; write(tube_serveur,&signal,sizeof(int)); write(tube_serveur,nom_tube[1],strlen(nom_tube[1])+1); write(tube_serveur,argv[2],1); close(tube_serveur); while (ferme!=2) pause(); }