image.png

image.png

Se observa que se lanza un hilo hijo sobre el hilo principal con una idea productor-consumidor. Mientras el hilo hijo agrega elementos al buffer (siempre y cuando la capacidad utilizada del mismo sea menor a N), el hilo principal intenta tomar elementos de él.

  1. Observo que se realiza un busy wait en ambos casos donde los hilos intentan tomar el lock sobre el buffer de manera constante en lugar de hacerlo de forma sincronizada en función de los recursos disponibles. Para el hilo hijo (productor) el “recurso disponible” equivale a la capacidad disponible del buffer, para el hilo principal (consumidor) este “recurso disponible” equivale a la presencia de elementos en el buffer. Una solución sería hacer uso de semáforos, uno para la cantidad de elementos en el buffer y otro para los espacios disponibles en el mismo. Inicialmente el valor de contador (V) para el semáforo de los elementos será 0, mientras que el del semáforo correspondiente a los lugares vacíos será N, en ambos casos el conjunto de procesos comenzará vacío (L) .
  2. En Rust, el MutexGuard (la variable buf) implementa el trait Drop. El lock se libera automáticamente cuando la variable sale de scope. Sin embargo, en un loop, el scope no termina hasta el final del bucle. Las llamadas explícitas a drop son necesarias porque los hilos se van a dormir (thread::sleep). Si no liberaran el buf antes del sleep, mantendrían el Mutex bloqueado, impidiendo que el otro hilo acceda al recurso, lo cual detendría el programa por completo.
sem_espacios_disponibles = Semaphore(N);
sem_elementos = Semaphore(0);
mutex_buffer = Mutex::new();

/* Hilo Productor (Hijo) */
loop {
    sem_espacios_disponibles.acquire();      // Espera si el buffer está lleno
    mutex_buffer.lock();
    buffer.push(dato);
    mutex_buffer.unlock();
    sem_elementos.release();      // Avisa que hay un nuevo elemento
}

/* Hilo Consumidor (Principal) */
loop {
    sem_elementos.acquire();      // Espera si el buffer está vacío
    mutex_buffer.lock();
    let dato = buffer.pop();
    mutex_buffer.unlock();
    sem_espacios_disponibles.release();      // Avisa que hay un espacio libre
}

image.png

image.png

  1. Falso, el estado interno de un actor es accesible únicamente por el mismo actor, siendo innecesario el uso de locks sobre ellos.
  2. Falso, por cada poll que se realiza sobre un Future se busca avanzar lo máximo posible el progreso de una tarea, es decir, hasta que deje de devolver Pending y devuelva Ready.
  3. Falso, en fork-join resolvemos subtareas a partir de tareas más complejas y la resolución de ellas es independiente a las resoluciones de las demás, por lo tanto haciendo uso de este modelo el resultado será determinístico.
  4. Falso, a los spurious wakeups, un hilo puede despertarse sin que ningún otro hilo haya emitido explícitamente una señal (notify/signal). Por este motivo, el despertar de un hilo no garantiza que la condición esperada sea verdadera ni que alguien lo haya llamado.

image.png