1. Para la primera parte realizamos un pequeño código que prueba la manera como funcionan los candados.
Lock *L = new Lock("testLock"); void printFunc(void* name) { int i = 0; L->Acquire(); for(i; i<=5; i++) { printf("[%s] Testing Locks - No. [%d]\n", (char *)name, i); } L->Release(); } void ThreadTest() { DEBUG('t', "Testing the lock and another things"); printf ("TESTING:\n\n"); const char* name; Thread* t1 = new Thread("Cecy"); name = t1->getName(); t1->Fork(printFunc, (void *)name); Thread* t2 = new Thread("Roberto"); name = t2->getName(); t2->Fork(printFunc, (void *)name); Thread* t3 = new Thread("Juan"); name = t3->getName(); t3->Fork(printFunc, (void *)name); }EJECUCIÓN 2. Para nuestra primera presentación práctica decimos dar solución al problema de productor
A) Solución usando candados:
Lock *L = new Lock("testLock"); int buffer = 0; void bufferState() { printf("Buffer = [ %d ]\n", buffer); } void producer(void* name) { while(true) { L->Acquire(); printf("[%s] producing data\n", (char *)name); buffer++; bufferState(); L->Release(); currentThread->Yield(); } } void consumer(void* name) { while(true) { L->Acquire(); while(buffer == 0) { L->Release(); currentThread->Yield(); } printf("[%s] consuming data\n", (char *)name); buffer--; bufferState(); L->Release(); } } void ThreadTest() { DEBUG('t', "Probando los candados y otras cosas"); printf ("Producer-Consumer:\n\n"); const char* name; Thread* t1 = new Thread("Cecy"); name = t1->getName(); t1->Fork(producer, (void *)name); Thread* t3 = new Thread("Juan"); name = t3->getName(); t3->Fork(producer, (void *)name); Thread* t2 = new Thread("Roberto"); name = t2->getName(); t2->Fork(consumer, (void *)name); }EJECUCIÓN B) Solución usando semáforos
Semaphore* s1 = new Semaphore("cecy", 1); Semaphore* s2 = new Semaphore("robert", 0); int buffer = 0; void bufferState() { printf("Buffer = [ %d ]\n", buffer); } void producer(void* name) { while(true) { s1->P(); printf("[%s] producing data [S]\n", (char *)name); buffer++; bufferState(); if(buffer == 1) { s2->V(); } s1->V(); currentThread->Yield(); } } void consumer(void* name) { int temp; s2->P(); while(true) { s1->P(); printf("[%s] consuming data. [S]\n", (char *)name); buffer--; temp = buffer; bufferState(); s1->V(); if(temp == 0){ s2->P(); } } } void ThreadTest() { DEBUG('t', "Probando los candados y otras cosas"); printf ("Productor-Consumidor con semaforos:\n\n"); const char* name; Thread* t1 = new Thread("Cecy"); name = t1->getName(); t1->Fork(producer, (void *)name); Thread* t2 = new Thread("Juan"); name = t2->getName(); t2->Fork(producer, (void *)name); Thread* t3 = new Thread("Roberto"); name = t3->getName(); t3->Fork(consumer, (void *)name); }EJECUCIÓN C) Solución usando Variables Condicionales
Lock* l1 = new Lock("l1"); Condition* c = new Condition("cecy", l1); int buffer; int limite = 10; void bufferState() { printf("Buffer = [ %d ]\n", buffer); } void anadir() { l1->Acquire(); while(buffer == limite) { c->Wait(); } buffer++; bufferState(); c->Signal(); l1->Release(); } void extraer() { l1->Acquire(); while(buffer == 0) { c->Wait(); } buffer--; bufferState(); c->Signal(); l1->Release(); } void producer(void* name) { while(true) { anadir(); printf("[%s] producing data [CV]\n", (char *)name); } } void consumer(void* name) { while(true) { extraer(); printf("[%s] consuming data [CV]\n", (char *)name); } } void ThreadTest() { DEBUG('t', "Probando los candados y otras cosas"); printf ("Productor-Consumidor con variables de condicion:\n\n"); const char* name; Thread* t1 = new Thread("Roberto"); name = t1->getName(); t1->Fork(producer, (void *)name); Thread* t2 = new Thread("Juan"); name = t2->getName(); t2->Fork(producer, (void *)name); Thread* t3 = new Thread("Cecy"); name = t3->getName(); t3->Fork(consumer, (void *)name); }EJECUCIÓN REFERENCIAS:
Nos basamos más que nada en los pseudocódigos vistos en las notas y en los libros de Stalling, Tanenbaum, y el de los dinosaurios :)