The pictures above show some results obtained when running the implemented code which is also described in it's more important parts.
Declaration of Lock class.
synch.h; /*Declaring class lock class Lock { public: // Constructor: Lock(const char* debugName); ~Lock(); // destructor const char* getName() { return name; } // Lock operations void Acquire(); void Release(); //checking that the current thread indeed has the lock bool isHeldByCurrentThread(); private: const char* name; //putting a Semaphore (our modification) Semaphore semaforo; };Implementation of Lock class.
synch.cc; Lock::Lock(const char* debugName) :name(debugName), semaforo("semaforo_lock", 1) //constructor { cout << "lock constructor\n"; } Lock::~Lock() { cout << "lock destructor \n";//destructor } void Lock::Acquire() { semaforo->P(); cout << "acquiring lock\n"; //debugging purposes } void Lock::Release() { semaforo->V(); cout << "releasing lock\n"; //debugging purposes }
Producer-Consumer bounded buffer implementation.
//apuntador a un lock compartido en todo el codigo Lock *l; Lock *l2; //lock usado para crear un deadlock Lock *l3; //lock usado para crear un deadlock Lock *consumidor; //usado para bloquear a los consumidores Lock *productor; //usado para bloquear a los productores Lock *modificarComestibles; //exclusion mutua entre productores y consumidores int comestibles; int maxComestibles; //se ejecuta la rutina para los consumidores void Consumidor(void *name){ char* threadName = (char*)name; bool tieneLock = false; while(1){ if(!tieneLock){ consumidor->Acquire(); tieneLock = true; } cout <<"comestibles: "<<comestibles << "\n"; if(comestibles > 0){ //podemos consumir productos //parte critica del codigo que se comparte entre todos los threads //sean productores o consumidores modificarComestibles->Acquire(); comestibles --; modificarComestibles->Release(); cout<<threadName<<" consumio\n"; consumidor->Release(); tieneLock = false; }else{ cout <<threadName <<" no puede consumir \n"; } currentThread->Yield(); } } //se ejecuta la rutina para los productores void Productor(void* name){ char* threadName = (char*)name; //cout <<"\nrutina del productor\n"; bool tieneLock = false; while(1){ if(!tieneLock){ productor->Acquire(); tieneLock = true; } cout <<"comestibles: "<<comestibles << "\n"; if(comestibles < maxComestibles){ //podemos producir //parte critica del codigo que se comparte entre todos los threads //sean productores o consumidores modificarComestibles -> Acquire(); comestibles ++; modificarComestibles -> Release(); cout<<threadName<<" produjo\n"; productor->Release(); tieneLock = false; }else{ cout <<threadName <<" no puede producir \n"; } currentThread->Yield(); } }
Fairness Test.
void PruebaFairness(void* name){ //parseando de tipo void a tipo char char* threadName = (char*)name; cout << "ejecutando Fairness para thread "<< threadName << "\n"; int repeticiones = 3; while(repeticiones >= 0 ){ cout << threadName <<" quiere el lock\n"; l->Acquire(); cout << threadName <<" tiene el lock\n"; l->Release(); repeticiones--; currentThread->Yield(); //despierta el primer thread en la cola // currentThread->Sleep();//manda el thread al final de la cola } }Liveness Test.
void PruebaLiveness(void* name){ char* threadName = (char*)name; srand(time(0)); float probabilidad; float pasa = 0.5; int a; int repeticiones = 0; while(repeticiones < 3){ probabilidad = (float)rand()/RAND_MAX ; if (probabilidad > pasa){ cout << threadName << " pide el lock\n"; l->Acquire(); cout << threadName << " tiene el lock\n"; for (int i = 0; i< 10000; i++){ a++; } for (int i = 0; i< 10000; i++){ a--; } l->Release(); cout << threadName << " libera el lock\n"; //cout << probabilidad<<endl; } currentThread->Yield(); repeticiones++; } }
Safety Test by making deadlock occur (on purpose).
void DeadLock1(void* name){ char* threadName = (char*)name; cout <<"\n"<<threadName <<" funciona de la siguiente manera\n"; cout <<"l2 Acquire()\n"; cout <<"l3 Acquire()\n"; cout <<"realiza operaciones criticas \n"; cout <<"l3 release()\n"; cout <<"l2 release()\n"; currentThread->Yield(); l2->Acquire(); cout <<"\n"<<threadName<<" Adquiere l2\n"; cout <<threadName<<" es interrumpido\n"; currentThread->Yield(); l3->Acquire(); cout<<"esta parte nunca va a pasar\n"; l3->Release(); l2->Release(); }
void DeadLock2(void* name){ char* threadName = (char*)name; cout <<"\n"<<threadName <<" funciona de la siguiente manera\n"; cout <<"l3 Acquire()\n"; cout <<"l2 Acquire()\n"; cout <<"realiza operaciones criticas \n"; cout <<"l2 release()\n"; cout <<"l3 release()\n"; currentThread->Yield(); l3->Acquire(); cout <<"\n"<<threadName<<" Adquiere l3\n"; cout <<threadName<<" es interrumpido\n"; currentThread->Yield(); l2->Acquire(); cout<<"esta parte nunca va a pasar\n"; l2->Release(); l3->Release(); }
Presentation.
Some pictures to show how our code works.
The picture above show how start the program (producer-consumer), initially the buffer is empty so if a consumer gets the first chance it will not be able of consume until some producer puts something in the buffer.
The next picture show us a case where the buffer gets full because of the producers, so while the buffer is full of products producers can not produces until some consumer liberate some space for the next unit, that's what happen with producer 3.
This last picture shows what happen after one consumer liberates space in the buffer, that way the next producer that try to producer can do it. In this case the producer that was blocked before (picture from above) now can produce and it does it.
While the program is running the threads (producers and consumers ) behave in a similar way. As you can see the quantity of products (comestibles) is always printed and in this program the maximum of products allowed in the buffer are 10 (you probably notice that).
Some notes:
Instead of putting -> in the post we are putting -">" operator.
Instead of using cout <<, we are using printf (don't forget this).
Those changes were made because of the code was not showed
in the way it supposed to be (some problems with the html).
We hope those changes do not confuse you to much and we fix that problem very soon :) .
Respecto a que no pudiste poner "<<", es porque al editar la entrada desde la pestaña "HTML" blogger piensa que si pones "<" estás colocando la abertura de un tag, entonces debes ponerlo con "<" =D
ReplyDeleteMuchas gracias, voy a ponerlos como deben de ir
ReplyDeleteY ponte unas capturas de pantalla, se ven bien los códigos, pero no vi la ejecución... estaba en un lugar no muy apto para eso :P
ReplyDeleteIgual le serviría a los compañeros que estaban viendo el Face, Twitter o lo que sea :).
Sería bueno que también aprovecharas la función isHeld... de los lock, por algo esta ahí, y puede ser útil en funciones con sincronizaciones mas complicadas.
Ok, voy a subir poner las capturas de pantalla para que luego las chequen.
ReplyDeleteTambién voy usar la función isHeld, porque creo que servira para las suguientes tareas
Una sugerencia checa bien el titulo de tu blog por que dice Soperativos :) y tambien espero esas capturas de pantalla concuerdo que se ven bien los codigos.
ReplyDeleteHola les quedo muy bien la presentación solo una sugerencia no podrían poner capturas de pantalla en la presentación de como corren un userprog
ReplyDeleteMuy bueno el ejemplo el de productor-consumidor
Hola :D
ReplyDeleteEn el destructor del Lock podría ir
Lock::~Lock() {
delete semaforo;
delete owner;
}
en vez de una simple impresión
En cuanto a las capturas de pantalla, ahorita las subo, apenas me desocupe.
ReplyDeleteEn cuanto a lo del titulo la intención es una un juego de palabras de Operativos y sopa, de ahi que soperativos =).
Por lo del destructor voy a agregar esa parte, estuve checando si ocupaba eliminar explicitamente los objetos que pertenecen a una clase pero estan como variables en otro y pues en todos lados encontre que el destructor de la clase que contiene a otras clases destruia automaticamente a sus variables de tipo clase.
Pero ahora que se como se hace de esa otra manera me parece mejor manejarlo explicitamente, gracias cecy =)..
Mmmm se me olvidaba con respecto al userprog aun no hemos podido correr código ahi, asi que lo que hicimos fue modificar el threadtest.cc para incluir el código de productor-consumidor en ese archivo.
ReplyDeleteEl primero que encuentre como hacer lo del userprog que lo ponga en piazza creo que hay muchos mas que quieren saber como se hace =).
Yo opino que en vez de capturas de pantalla, las salidas también podrían ir con el syntax highlighter (aunque sin colores) para que tengan números de línea - eso ayuda al discutirlas.
ReplyDeletePunto extra para Cecy.