1 Uso de variables de condición como mecanismo de sincronización.

De esta práctica vamos a crear dos versiones del mismo ejercicio. Una en lenguaje C haciendo uso de posix threads y la otra en lenguaje Rust.

Se nos pide escribir un programa que creará un número N de hilos sincronizados de manera que cada uno de ellos almacene una serie de valores en un vector de enteros.

Estos valores a escribir se encontrarán entre uno inicial y uno final (ambos incluidos) que se conocerán cuando comience la ejecución del programa. La cantidad de elementos a escribir en el vector será mayor que el número de hilos creados.

El hilo principal se encargará de crear el vector y los N hilos además de imprimir en el terminal los contenidos del vector desde la primera a la última componente una vez hayan terminado todos los hilos. De esta manera podremos comprobar que la ejecución se ha realizado de forma correcta.

Cada uno de los hilos escribirá alternativamente y en orden los valores que le correspondan comprendidos entre el inicial y el final.

Si llamamos N al número de hilos, s al valor inicial y e al valor final entonces el hilo i-ésimo escribirá los valores \(s+i\), \(s+N+i\), \(s+2N+i\), … y así sucesivamente, por tanto cada hilo terminará cuando el valor que le toque escribir sea mayor que e.

Estos hilos sincronizarán su ejecución mediante el uso de una única variable de condición.

Una vez acabados todos los hilos los datos en el vector serán: s, s+1, s+2, s+3, ... , e, es decir, todos los números en orden entre s y e

Veamos una representación gráfica de la evolución de este algoritmo a lo largo del tiempo para valores de N=3, s=1 y e=11:

2 Ejemplos de uso de variables de condición

2.1 Posix Threads

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// gcc -g condvarexample.c -o condvarexample
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#include <stdbool.h>

bool condition = false;
pthread_cond_t condv = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* worker_thread(void* arg) {

  pthread_mutex_lock(&mutex);
  while (!condition) {
    printf("ESPERANDO CONDICION (condition == TRUE)\n");
    pthread_cond_wait(&condv, &mutex);
  }
  pthread_mutex_unlock(&mutex);

  printf("La condición se ha cumplido, por lo que el hilo puede continuar.\n");

  return NULL;
}

int main() {
  pthread_t thread;

  // Vamos a manipular 'condition', usamos el mutex.
  pthread_mutex_lock(&mutex);
  // Inicializamos la condición a false.
  condition = false;
  pthread_mutex_unlock(&mutex);

  //printf("Creamos el hilo trabajador.\n");
  pthread_create(&thread, NULL, worker_thread, NULL);

  // Esperamos 1sg.
  sleep(1);
  // Y cumplimos la condición.
  // Vamos a manipular 'condition', usamos el mutex.
  pthread_mutex_lock(&mutex);
  condition = true;
  pthread_cond_signal(&condv);
  pthread_mutex_unlock(&mutex);


  // Esperamos a que el hilo trabajador termine.
  pthread_join(thread, NULL);

  return 0;
}

2.2 Rust

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// rustc -g condvarexample.rs
use std::sync::{Arc, Mutex, Condvar};
use std::thread;
use std::time::Duration;

fn main() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair2 = Arc::clone(&pair);

    // Inside of our lock, spawn a new thread, and then wait for it to start.
    thread::spawn(move || {
        let (lock, cvar) = &*pair2;
        let onesec = Duration::from_secs(1);
        thread::sleep(onesec);
        let mut started = lock.lock().unwrap();
        *started = true;
        // We notify the condvar that the value has changed.
        cvar.notify_one();
    });

    // Wait for the thread to start up.
    let (lock, cvar) = &*pair;
    let mut started = lock.lock().unwrap();
    while !*started {
        started = cvar.wait(started).unwrap();
    }
    println!("La condición se ha cumplido, por lo que el hilo puede continuar.");
}

3 Entrega

  • Se realiza en pracdlsi en las fechas allí indicadas. Puedes entregar tantas veces como quieras, solo se corrige la ultima entrega.

  • Los documentos que entregues deben ser de texto (UTF-8 preferiblemente) o PDF, no emplees otros formatos.

  • Crea una carpeta llamada p7 y dentro de ella estarán el código y archivos de texto o PDF donde contestas a las preguntas. Esta carpeta la comprimes en un archivo llamado p7.tgz p.e. así usando el terminal:

    tar cfz p7.tgz p7