Mostrando entradas con la etiqueta threads. Mostrar todas las entradas
Mostrando entradas con la etiqueta threads. Mostrar todas las entradas

jueves, 6 de febrero de 2014

Ejemplo #3 - [Threads] Regiones críticas: El problema de los jardines

#include <pthread.h>
#include <stdio.h>

long Visitantes = 0;
pthread_mutex_t mutex;

void IncVisitantes() {
   pthread_mutex_lock(&mutex);
   Visitantes = Visitantes + 1;
   pthread_mutex_unlock(&mutex);
}

void *HebraVisitas (void *argg) {
   int i=0;

   long *NumVisitas;

   NumVisitas = (long *) argg;

   for (i=0; i<*NumVisitas;i++) {
      IncVisitantes();
   }
}


int main () {
   pthread_t th1, th2, th3, th4;
   pthread_attr_t attr;
   long visi1 = 1000000;
   long visi2 = 2000000;

   pthread_attr_init(&attr);
   pthread_mutex_init(&mutex, NULL);

   pthread_create(&th1, &attr, HebraVisitas, &visi1);
   pthread_create(&th2, &attr, HebraVisitas, &visi2);
   pthread_create(&th3, &attr, HebraVisitas, &visi1);
   pthread_create(&th4, &attr, HebraVisitas, &visi2);
   pthread_join(th1, NULL);
   pthread_join(th2, NULL);
   pthread_join(th3, NULL);
   pthread_join(th4, NULL);

   printf("El numero de visitas totales =%ld\n", Visitantes);
   printf("Fin\n");
   return 0;
}

Probad a realizar el ejercicio sin usar mutex y ampliando el número de visitantes. Comentar los resultados :D

[Threads] Regiones críticas

POSIX ofrece diversos mecanismos para interactuar con las regiones críticas entre hebras, nosotros nos centraremos en uno de los más sencillos e intuitivos, el mutex.

int pthread_mutex_init(pthread_mutex_t *restrict mutex, 
                       const pthread_mutexattr_t *restrict attr);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_mutexattr_init(pthread_mutexattr_t *attr);

Si los attr son NULL, será un mutex con atributos por defecto. Se inicializa a desbloqueado y además debemos destruirlo a desbloqueado.

int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_trylock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);

La función "pthread_mutex_trylock" intenta tomar un mutex. Si ya está bloqueado se devuelve un código de error EBUSY (puede resultar útil para evitar condiciones de deadlock).

Al intentar desbloquear se pueden devolver dos tipos de errores:
  • Si el mutex ya está desbloqueado.
  • Si el mutex está tomado por otra hebra.



Ejemplo #1 - [Threads] Creación/Terminación

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

#define NUM_THREADS 5

void *PrintHello(void *threadid){
   long tid;
   tid = *(long*)threadid;
   printf("Hello World! It's me, thread #%ld!\n", tid);
   pthread_exit(NULL);
}

int main (int argc, char *argv[]){
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   
   for (t=0; t<NUM_THREADS; t++){
      printf("In main: creating thread %ld\n", t);
      rc = pthread_create(&threads[t], NULL, PrintHello, &t);
      if (rc) {
         printf("ERROR; return code from pthread_create() is %d\n", rc);
         exit(-1);
      }
   }
   pthread_exit(NULL);
}

Para la implementación de este sencillo ejemplo no tenemos que tener muchas cosas en cuenta, únicamente tener cuidado con el paso de parámetros que referencian a bloques de memoria. En nuestro caso, en primer lugar le pasamos como primer parámetro el thread que vamos a construir, acto seguido la estructura del thread, como tercer parámetro el manejador o la función que vayamos a utilizar y por último el argumento para nuestra función.