Tuesday, September 13, 2011

First practical presentation

This entry is for presenting the code implemented in nachOS as part of the first assignment.
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 :) .

10 comments:

  1. 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

    ReplyDelete
  2. Muchas gracias, voy a ponerlos como deben de ir

    ReplyDelete
  3. Y 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

    Igual 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.

    ReplyDelete
  4. Ok, voy a subir poner las capturas de pantalla para que luego las chequen.
    También voy usar la función isHeld, porque creo que servira para las suguientes tareas

    ReplyDelete
  5. 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.

    ReplyDelete
  6. Hola 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

    Muy bueno el ejemplo el de productor-consumidor

    ReplyDelete
  7. Hola :D
    En el destructor del Lock podría ir
    Lock::~Lock() {
    delete semaforo;
    delete owner;
    }

    en vez de una simple impresión

    ReplyDelete
  8. En cuanto a las capturas de pantalla, ahorita las subo, apenas me desocupe.

    En 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 =)..

    ReplyDelete
  9. 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.

    El primero que encuentre como hacer lo del userprog que lo ponga en piazza creo que hay muchos mas que quieren saber como se hace =).

    ReplyDelete
  10. 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.
    Punto extra para Cecy.

    ReplyDelete