/** * * @File : exo_01.cxx * * * @Author : A. Dragut * * @Synopsis : Producteur-Consommateur lies par fork() et pipe() * **/ #include #include #include #include // strlen() #include // PIPE_BUF #include // sleep(), getpid() #include "CExc.h" // exceptions fonctions systemes #include "nsSysteme.h" //appels systemes using namespace std; using namespace nsSysteme; //utilisation de la bibliotheque nsSysteme int main(int argc, char * argv []) { try { if (argc <= 1) throw CExc("main()",string ("Usage : ") + argv [0] + " "); //creation d'un pipe/tuyau int pfd [2]; Pipe (pfd); pid_t pidConsom; int TailleMessage; //en octets //Creation d'un nouveau processus avec lequel on va partager //le pipe/tuyau parce que les descripteurs de "fichiers" //ouverts sont herites entre le pere et le fils if (0 != (pidConsom = Fork()) ){//Pere Producteur //Fork() renvoie un vrai pid, pidConsom >0 , dans le pere //dans le pere on ne va utiliser que le bout d'ecriture du pipe //on ferme le bout de lecture du pipe int & pfdEcriture = pfd[1]; Close (pfd [0]); //protocole de communication for (int i = 1; i < argc; ++i) { //la taille du message ecrit dans le pipe TailleMessage = strlen (argv [i]); //ecriture de la taille en octets Write (pfdEcriture, &TailleMessage, sizeof (int)); //ecriture du message Write (pfdEcriture, argv [i], TailleMessage); } //le pere producteur connait le nombre de messages a envoyer //mais le fils ne va pas savoir quand il doit s'arreter //si on ne lui annonce pas la fin //protocole de fin de communication //fin annoncee TailleMessage = 1; char Fin='#'; Write (pfdEcriture, &TailleMessage, sizeof (int)); Write (pfdEcriture,&Fin, TailleMessage); //fermeture complete de pipe //fin effective //le producteur ne doit plus ecrire apres que le //consommateur a ferme son bout de pipe, sinon //le producteur recoit un SIGPIPE // mais le producteur peut fermer son bout de pipe // a tout moment, independamment du consommateur Close (pfdEcriture); //un fournisseur de services n'as pas le droit de creer de zombies //le producteur doit recuperer le statut de son fils //ou bien employer sigaction(SIGCHLD,&act,0) //avec act.sa_flags=SA_NOCHLDWAIT int status; cout << "Pere : j'attends la fin de mon fils consommateur" << endl; Waitpid(pidConsom,&status,0); if (WIFEXITED(status)) { cout << "Pere : l'etat du consommateur est " << WEXITSTATUS(status) << endl; } } // Fin Pere Producteur else {//Fils Consommateur //Fork() renvoie un 0, pidConsom =0 , dans le fils //dans le fils on ne va utiliser que le bout de lecture du pipe //on ferme le bout d'ecriture du pipe int & pfdLecture = pfd [0]; Close (pfd [1]); int VraieFinPasRecue = 1; while (VraieFinPasRecue) { //tant que on n'as pas recu '#' on continue int OctetsLus = Read (pfdLecture, &TailleMessage, sizeof (int)); char Message [TailleMessage + 1]; if(OctetsLus) { int TailleMessageReelle = Read (pfdLecture, Message, TailleMessage); Message[TailleMessageReelle] = '\0'; if((1 == TailleMessage) && ('#' == Message[0])) { VraieFinPasRecue = 0; cout << "Fin de communication annoncee par '#'" << endl; } else { cout << "Le Consommateur fils id : " << ::getpid() << " a lu : " << Message << endl; } } else { VraieFinPasRecue = 0; cout << "Fin de communication imprevue. " << endl; cout << "Le pere producteur a ferme son pipe" << endl; //le producteur a deja ferme son pipe/tuyau //donc on peut fermer tout de suite } } //Fin de communication du cote fils consommateur Close (pfdLecture); return 0; } // Fin Fils Consommateur } catch (const CExc & Exc) { cerr << Exc << endl; return errno; } catch (const exception & Exc) { cerr << "Exception : " << Exc.what () << endl; return 1; } catch (...) { cerr << "Exception inconnue recue dans la fonction main()" << endl; return 1; } } // main()