/* Le programme "banque" Synopsis : banque [] Parametres : contient un numero de compte (compris entre 0 et 9) contient 'L' pour Lire le compte 'M' pour Modifier le compte de (NB: pour crediter un compte, on met 'M' et un negatif n'est utilise que quand vaut 'M'. Il correspond au montant a debiter Exemples : banque 5 L affiche le solde du compte numéro 5 banque 3 M 50.5 modifie en debitant le compte numero 3 de 50.5 NB : Cette version avec gestion de verrous n'est pas optimale d'un point de vue deadlock, puisque les processus ne prennent pas tout de suite le plus fort verrou qu'ils auront besoin de prendre. Heureusement, Unix detecte ca a l'execution : si on lance en parallele, 2 banqueQ4 0 M 100 l'un des processus fait tentative de pose de verrou (partage) par processus 11214... ...Verrou (partage) pose par 11214 Solde initial du compte 0 = -200.00 tentative de pose de verrou (exclusif) par processus 11214... ... Verrou (exclusif) pose par processus 11214 Relachement verrou par processus 11214... ...OK tandis que l'autre fait: tentative de pose de verrou (partage) par processus 11215... ...Verrou (partage) pose par 11215 Solde initial du compte 0 = -200.00 tentative de pose de verrou (exclusif) par processus 11215... Pose verrou: Resource deadlock avoided */ #include #include #include #include #include #include #include #include #include #define NOMFICHIER "./banque.dat" #define NBCOMPTES 10 #define FATAL(msg) { \ fprintf(stderr,"%s:%s %s:%d:%s\n", \ strerror(errno), msg, \ __FILE__, __LINE__, __func__);\ abort(); \ } int main(int argc, char *argv[]){ int numCompte; char typeOp; double montant; double solde; /* Declarations de variables a ajouter */ int fd; int nbR, nbW; int i; int rc; struct flock verrou; /* Lecture des parametres */ if ((argc < 3) || (argc>4)){ fputs("USAGE : banque []\n", stderr); return EXIT_FAILURE; } numCompte = atoi(argv[1]); if ((numCompte<0) || (numCompte>=NBCOMPTES)){ fputs("USAGE : banque []\n", stderr); fputs(" doit etre compris entre 0 et 9 (inclus)\n", stderr); return EXIT_FAILURE; } typeOp = toupper(argv[2][0]); if ((typeOp != 'L') && (typeOp != 'M')){ fputs("USAGE : banque []\n", stderr); fputs(" doit valoir 'L' ou 'M'\n", stderr); return EXIT_FAILURE; } if (typeOp == 'M'){ if (argc != 4){ fputs("USAGE : banque []\n", stderr); fputs(" est obligatoire quand vaut 'M'\n", stderr); return EXIT_FAILURE; }else{ montant = atof(argv[3]); } } /* Ouvrir le fichier "compte.data" (si ce fichier n'existe pas, on le cree de sorte qu'il contienne NBCOMPTES comptes (sous la forme de NBCOMPTES soldes à 0) */ fd = open(NOMFICHIER, O_RDWR, 0); if (fd < 0){ if (errno == ENOENT){ /* Le fichier n'existe pas : on le cree donc */ fd = open(NOMFICHIER, O_CREAT|O_RDWR, S_IRUSR|S_IWUSR ); if (fd < 0){ FATAL("open fichier"); } /* On le remplit */ solde = 0; for (i=0 ; i On peut lire le fichier */ rc = lseek(fd, numCompte*sizeof(double), SEEK_SET); if (rc < 0){ FATAL("lseek"); } nbR = read(fd, &solde, sizeof(solde)); if (nbR != sizeof(double)){ FATAL("read"); } /* On l'affiche */ printf("Solde initial du compte %d = %10.2f\n", numCompte, solde); /* On dort un peu (pour laisser le temps a d'autres processus de s'executer */ sleep(5); /* On effectue l'operation */ if (typeOp == 'L'){ /* Nouvelle consultation du solde de ce compte dans le fichier */ rc = lseek(fd, numCompte*sizeof(double), SEEK_SET); if (rc < 0){ FATAL("lseek"); } nbR = read(fd, &solde, sizeof(solde)); if (nbR != sizeof(double)){ FATAL("read"); } /* Nouvel affichage */ printf("Solde du compte %d = %10.2f\n", numCompte, solde); }else{ /* Debit */ solde -= montant; /* On ecrit le nouveau solde dans le fichier */ rc = lseek(fd, numCompte*sizeof(double), SEEK_SET); if (rc < 0){ FATAL("lseek"); } nbW = write(fd, &solde, sizeof(double)); if (nbW != sizeof(solde)){ FATAL("pb write solde"); } } /* Liberation du verrou */ printf("Relachement verrou par processus %d...\n", getpid()); if (fcntl(fd, F_UNLCK, &verrou) < 0){ perror("Relachement verrou"); exit(EXIT_FAILURE); } printf("...OK\n"); /* On referme le fichier */ rc = close(fd); if (rc < 0){ FATAL("close"); } return EXIT_SUCCESS; }