Examen final de Ampliación de sistemas operativos, Fila A. Febrero de 2009 Tercer curso de Ingeniería técnica de informática de sistemas Tiempo total: 2 horas. Problema: Cuarto de baño unisex En una conocida discoteca de Móstoles hay un cuarto de baño unisex, es decir al que pueden acceder hombres y mujeres, aunque en este caso no simultáneamente. Se nos pide diseñar el programa que controlará el acceso a este cuarto de baño. Este programa ejecutará en un dispositivo con dos botones. Un botón será utilizado por las mujeres para pedir la entrada al baño. El otro por los hombres. Al apretar el botón se imprimirá un papel con el número de turno. Cuando su número aparezca en la puerta general del baño, los hombres y mujeres, que a partir de ahora denominaremos usuarios podrán entrar. Simule los usuarios como procesos concurrentes que compartan memoria y que pueden estar fuera del baño, esperando, haciendo uso de él o fuera satisfechos. Debe controlar que solo accedan al baño usuarios de un solo género y que como mucho entren 5 simultáneamente que es la capacidad del baño. Dicho de otra forma, sólo pueden entrar al baño hombres o mujeres pero no hombres y mujeres simultáneamente y como mucho puede haber 5 usarios a la vez en el baño. El programa debe ser justo, es decir, no puede existir hambruna. Utilice para crear los procesos la librería de thread(2) y semáforos nativos del sistema Plan 9. NOTA: Tanto este problema como el problema de la cafetera/tetera son en realidad el mismo problema. Por tanto, estas soluciones (se incluyen dos) también son soluciones para el problema de la cafetera/tetera. -2- Solución Esta solución es más compacta, pero puede ser más difícil de entender: __________ toiletsem.c #include <u.h> #include <libc.h> #include <thread.h> // 8c -FVw toiletsem.c && 8l -o toiletsem toiletsem.8 // kill toiletsem|rc enum{ Stacksize = 8*1024, NSEATS = 5, Masc= 0, Fem, Maxgen, Nogender, }; long turn = 1; long serial[Maxgen] = { 1, 1, }; long seat = NSEATS; long door = 1; int npeople; long nticmutex = 1; int nticket; void user(void *g) { int nt, gender; gender = (int)g; semacquire(&turn, 1); semrelease(&turn, 1); semacquire(&nticmutex, 1); nt = nticket++; semrelease(&nticmutex, 1); //I could use turn, but this is cleaner print("your ticket number is %d\n", nt); -3- semacquire(&serial[gender], 1); if(npeople++ == 0){ semacquire(&turn, 1); semacquire(&door, 1); semrelease(&turn, 1); } semrelease(&serial[gender], 1); semacquire(&seat, 1); print(" %d of gender %d has entered and is doing things\n", nt, gender); sleep(100); semrelease(&seat, 1); semacquire(&serial[gender], 1); if(--npeople == 0) semrelease(&door, 1); print(" %d of gender %d left\n", nt, gender); semrelease(&serial[gender], 1); } void threadmain(int, char *[]) { int g, i; srand(2); //no realmente aleatorio, repetible for(i = 0; i < 100; i++){ g = nrand(Maxgen); print("A user of gender %d pressed a button\n", g); proccreate(user, (void *)g, Stacksize); } threadexits(nil); } Esta otra solución es más clásica. ___________ toiletsem2.c #include <u.h> #include <libc.h> #include <thread.h> // 8c -FVw toiletsem2.c && 8l -o toiletsem toiletsem2.8 enum{ Stacksize = 8*1024, NSEATS = 5, Masc= 0, Fem, Maxgen, Nogender, }; -4- long mutex = 1; long seats[Maxgen]; int npeople[Maxgen]; int npeoplein; int toiletgen = Nogender; int nticket; char *gennames[Maxgen] = { //para depurar [Masc] "Masc", [Fem] "Fem", }; int total(void) { int t, i; t = 0; for(i = 0; i<Maxgen; i++) t += npeople[i]; return t; } int other(int gen) { return (gen+1)%Maxgen; } int max(int a, int b) { if( a > b) return a; else return b; } void user(void *g) { int gender, genother, mytick; gender = (int)g; genother = other(gender); -5- semacquire(&mutex, 1); mytick = nticket++; print("your ticket number is %d\n", mytick); if(toiletgen == Nogender){ toiletgen = gender; npeoplein = max(NSEATS, npeople[gender]); semrelease(&seats[gender], npeoplein); print("gender of the toilet is %s \n", gennames[gender]); } else if(toiletgen == gender && npeoplein < NSEATS){ npeoplein++; semrelease(&seats[gender], npeoplein); } npeople[gender]++; semrelease(&mutex, 1); semacquire(&seats[gender], 1); print("Doing my things, I am a %s, with ticket %d \n", gennames[gender], mytick); sleep(100); semacquire(&mutex, 1); npeoplein--; npeople[gender]--; if(!npeople[genother]){ semrelease(&seats[gender], 1); } else if(!npeoplein && npeople[genother]){ toiletgen = genother; npeoplein = max(NSEATS, npeople[genother]); semrelease(&seats[genother], npeoplein); } else if(!npeoplein && total() == 0){ toiletgen = Nogender; } semrelease(&mutex, 1); } void threadmain(int, char *[]) { int g, i; srand(2); //no realmente aleatorio, repetible for(i = 0; i < 30; i++){ g = nrand(Maxgen); print("A user of gender %s pressed a button\n", gennames[g]); proccreate(user, (void *)g, Stacksize); } threadexits(nil); }