Sunday, May 20, 2012

Locks


Imagen de http://9gag.com/gag/4100321

Formato de la tarea:
  • Tomar una foto a los pasos 4 y 5 como se muestra en el ejemplo
  • Ponerlas en formato pdf
  • Enviarlas al correo electronico: sistemas.operativos.fime@gmail.com
  • Asunto: HORA - Tarea 4 - Matricula - Nombre
  • Entregarla antes del jueves 23 de mayo
Correo que no tenga el formato correcto NO sera revisada.

1.- Implementar Locks en NachOS

Bueno lo primero que tenemos que hacer es abrir nuestra terminal y ir a nuestra carpeta de threads


cd nachos/nachos/code/threads

Bueno para la implementación de los Locks editaremos los archivos synch.cc y synch.h.

sudo gedit synch.h


Buscamos la linea 89 y depues de donde dice:

  private:
    const char* name;    // para depuraci�n
Agregaremos Semaphore semaforo;
  private:
    const char* name;    // para depuraci�n
Semaphore semaforo;

Ahora editaremos el synch.cc
sudo gedit synch.cc
Al principio agregamos:
#include <iostream>

Buscamos donde viene Locks debe verse algo asi
// Dummy functions -- so we can compile our later assignments 
// Note -- without a correct implementation of Condition::Wait(), 
// the test case in the network assignment won't work!
Lock::Lock(const char* debugName) {}
Lock::~Lock() {}
void Lock::Acquire() {}
void Lock::Release() {}

Una vez que implementamos los Locks deberia verse asi:
Lock::Lock(const char* debugName)
  :name(debugName), semaforo("semaforo_lock", 1) //constructor
{
  printf("lock constructor\n");
}
Lock::~Lock() 
{
 printf("lock destructor \n");//destructor
}
void Lock::Acquire() {
  semaforo.P();
  printf("acquiring lock\n"); //debugging purposes 
}
void Lock::Release() {
  semaforo.V();
  printf("releasing lock\n"); //debugging purposes

}
 


2.- Crear un programa que corra Locks

Bueno para esto abriremos el archivo threadtest.cc.

sudo gedit threadtest.cc
Lo primero que tenemos que agregar son las librerias nuevas
#include "synch.h" //agregado para ejecutar los locks
#include <iostream>
using namespace std;
#include <ctime>
#include <cstdlib>

Ahora antes de:
void
SimpleThread(void* name)
{
    // Reinterpret arg "name" as a string
    char* threadName = (char*)name;
    
    // If the lines dealing with interrupts are commented,
    // the code will behave incorrectly, because
    // printf execution may cause race conditions.
    for (int num = 0; num < 10; num++) {
        //IntStatus oldLevel = interrupt->SetLevel(IntOff);
 printf("*** thread %s looped %d times\n", threadName, num);
 //interrupt->SetLevel(oldLevel);
        //currentThread->Yield();
    }
    //IntStatus oldLevel = interrupt->SetLevel(IntOff);
    printf(">>> Thread %s has finished\n", threadName);
    //interrupt->SetLevel(oldLevel);
}

Agregaremos los Siguientes codigos:

Codigo del Productor Consumidor
//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();
  }


}

  

Prueba Fairness.
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
  }
}
 
Prueba Liveness.
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++;
  }
}
 

Prueba Safety (con esta aremos un deadlock).
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();

}

Despues de Agregarlos buscamos el que dice ThreadTest() y en este agregaremos /* y */ para que no ejecute el SimpleTest(), debe quedar como en la siguiente imagen.

Despues del */ y antes de agregamos el siguiente codigo:


        int n = 10;
    int p = 3; //cuantos productores
    int c = 2;// cuantos consumidores
    l = new Lock("lock1");
    l2 = new Lock("lock2");
    l3 = new Lock("lock3");
    modificarComestibles = new Lock("comestibles");//bloquea productores y consumidores
    consumidor = new Lock("consumidor");//bloquea consumidores
    productor = new Lock("productor");//bloquea productores
    comestibles = 0; //cero comestibles 
    maxComestibles = 10; //maximo de productos que podemos tener en cola
    
    cout << "*------------->Ejecutando prueba para Fairness<-------------*\n";
    for ( int k=1; k<=n; k++) {
      char* threadname = new char[100];
      sprintf(threadname, "Hilo %d", k);
      Thread* newThread = new Thread (threadname);
      newThread->Fork (PruebaFairness, (void*)threadname);
    }
    
    PruebaFairness( (void*)"Hilo 0");

    //se realiza la prueba de livenes "si varios threads piden un lock
    //al mismo tiempo al menos uno lo debe de obtener"
    cout << "\n*------------->Ejecutando prueba para Liveness<-------------*\n";
    for ( int k=1; k<=n; k++) {
      char* threadname = new char[100];
      sprintf(threadname, "Hilo %d", k);
      Thread* newThread = new Thread (threadname);
      newThread->Fork (PruebaLiveness, (void*)threadname);
    }
    
    PruebaLiveness((void*)"Hilo 0");
    

    // Productor((void*)"Productor0");
/*
   
    cout << "\n*------------->Ejecutando prueba para Safety<-------------*\n";
    for ( int k=1; k<=1; k++) {
      char* threadname = new char[100];
      sprintf(threadname, "Hilo %d", k);
      Thread* newThread = new Thread (threadname);
      newThread->Fork (DeadLock2, (void*)threadname);
    }
    
    DeadLock1((void*)"Hilo 0");
  */ 
    cout <<"\n*------------->Ejecutando el programa del productor consumidor<-------------*\n";
    
     cout << "\ncreando productores\n";
     for ( int k=1; k<=p; k++) {
       char* threadname = new char[100];
       sprintf(threadname, "Productor %d", k);
       Thread* newThread = new Thread (threadname);
       newThread->Fork (Productor, (void*)threadname);
     }
     
     cout << "\ncreando consumidores\n";
     for ( int k=2; k<=c; k++) {
       char* threadname = new char[100];
       sprintf(threadname, "Consumidor %d", k);
       Thread* newThread = new Thread (threadname);
       newThread->Fork (Consumidor, (void*)threadname);
     }

    Consumidor((void*)"Consumidor 1");


3.- Compilar
Bueno aqui tecleamos en la terminal lo siguiente:
cd ..

Y ahora si le damos make.
make
4.- Primera prueba correr nachOS. 
Suponiedo que no marco algun error volvemos a la carpeta de threads y para correrlo le tecleamos:
cd threads

y lo corremos

./nachos
Esta prueba deberia correr PruebaFairnessPruebaLiveness y el Consumidor Productor. La ejecución deberia verse de la siguiente manera:
Imagen para la tarea.

5.- Causar un DeadLock.

Para matar el proceseso presionamos Ctrl C, y despues abrimos el archivo threadtest.cc y borraremos el /* y */ del DeadLock como en la siguiente imagen:


Ahora lo siguiente es volver a compilar nachOS, tecleamos en la terminal lo siguiente:
cd ..

Y ahora si le damos make.
make

Suponiedo que no marco algun error volvemos a la carpeta de threads y para correrlo le tecleamos:
cd threads
y lo corremos
./nachos

Una vez que corremos nachOS deberia verse algo asi:
Imagen para la tarea.



Informacion y codigos de: http://sistemassoperativos.blogspot.mx/2011/09/first-practical-presentation.html

No comments:

Post a Comment