Modelos de multihebras

De Departamento de Informatica
Saltar a: navegación, buscar

Contenido

Contenidos

Introducción

Como bien se anticipó en Motivación Y Ventajas de Hebras, Podemos indicar básicamente que hablamos de un pequeño conjunto de instrucciones que se ejecutan de manera independiente dentro del proceso y que hace uso de los recursos de este. También se hizo mención de ¿por qué utilzarlas?

Ilustración Threads dentro de un proceso


En donde dicha interrogante dentro de sus respuestas incluye un aumento del rendimiento del sistema y la posibilidad de realizar multiples tareas de manera simultánea.

Aquello no termina allí, debemos realizar otra separación, la cual se refiere a los threads de usuarios y threads de Kernel. Es en este punto en donde nos centraremos ya que la forma de interactuar entre ambos tipos de threads, puede ser de múltiples formas, lo cuál detallaremos a continuación.

Modelo Muchos a uno (Hebras a nivel de usuario)

Esquema del modelo muchos a uno

Un modelo Muchos a uno implica que todas las hebras creadas a nivel de aplicación corresponde con solo una entidad a nivel de kernel, este no tiene conocimiento de las hebras a nivel de aplicacion. Con este metodo, el "context swiching" puede realizarse muy rápidamente y hasta puede ser implementado en kernels que no soportan el uso de hebras. Una de sus mayores deficiencias es que no se beneficia de la aceleración proporcionada de procesadores multihebra o multiprocesadores, nunca hay más de una hebra procesandose al mismo tiempo. Por ejemplo: si una de las hebras necesita ejecutar una peticion I/O, el proceso entero es detenido. Las librerias GNU Portable Threads y Solaris green Threads usan hebras a nivel de usuario.

Ventajas

  • El intercambio de los hilos no necesita los privilegios del modo kernel, porque todas las estructuras de datos están en el espacio de direcciones de usuario de un mismo proceso. Por lo tanto, el proceso no debe cambiar a modo kernel para gestionar hilos. Se evita la sobrecarga de cambio de modo y con esto el sobrecoste u overhead.
  • Se puede realizar una planificación específica. Dependiendo de que aplicación sea, se puede decidir por una u otra planificación según sus ventajas.
  • Los ULT pueden ejecutar en cualquier sistema operativo. La biblioteca de hilos es un conjunto compartido.

Desventajas

  • En la mayoría de los sistemas operativos las llamadas al sistema (System calls) son bloqueantes. Cuando un hilo realiza una llamada al sistema, se bloquea el mismo y también el resto de los hilos del proceso.
  • En una estrategia ULT pura, una aplicación multihilo no puede aprovechar las ventajas de los multiprocesadores. El núcleo asigna un solo proceso a un solo procesador, ya que como el núcleo no interviene, ve al conjunto de hilos como un solo proceso.

Una solución al bloqueo mediante llamadas al sistema es usando la técnica de jacketing, que es convertir una llamada bloqueante en no bloqueante.

Modelo uno a uno

Temas creados por el usuario están en correspondencia de 1-1 con entidades programables en el nucleo. Esta es la implementación de roscado simple posible. Win32 utiliza este enfoque desde el principio. En Linux, la biblioteca C usual implementa este método ( a través de la NPTL o mayores LinuxThreads). El mismo método es utilizado por Solaris, NetBSD y FreeBSD.

Los puntos mas destacados de este modelo son:

  • Cada hebra del usuario tiene una hebra del kernel.
  • Mayor concurrencia que el modelo muchos es a muchos.
  • Solo se bloquea la hebra que hace una llamada bloqueante.
  • Múltiples hebras en paralelo sobre varios procesadores.
  • Carga administrativa al crear hebras del kernel. Captura.JPG
Esquema de uno es a uno ( una hebra de usuario a un kernel )


Modelo Muchos a Muchos

Ejemplo de Muchos a muchos

Como es posible de apreciar, lo característico de este modelo es el hecho que muchos threads de usuario, confluyen en el itinerador de Threads (LWP), el cual deriva aquello en multiples threads creados por el kernel para poder cumplir con dicho propósito.


Ahora bien, veamos esto en la práctica, como se ha visto en los ejemplos anteriores, lo común es que el sistema automáticamente cree un thread de kernel por cada thread de usuario o sencillamente utilizan el método muchos a uno. En linux desde el kernel 2.6 está disponible el soporte para el manejo de threads de kernel[1] la cual es la parte un poco mas compleja, ya que los threads de usuario los podemos crear sin mayores problemas.


Para resolver esto utilizaremos la libreria thread en c, que nos soluciona el problema con los threads de usuario, ahora para los threads de kernel utilizaremos una llamada de sistema llamada clone() o clone2() que participan en la ayuda de un proceso hijo, pero a diferencia de fork() tenemos más control acerca del comportamiento del proceso hijo por ejemplo: si deseamos que el nuevo hijo comparta la misma información del archivo de sistema, tabla descriptora del archivo, entre otros. Es más como dato anecdótico las librerias de threads hacen uso de la función clone(), para crear los nuevos threads.

A continuación analizaremos un pequeño programa que crea múltiples hilos de kernel y que puedes copiar en un archivo y testearlo en tu consola:

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

void * function1(void *arg){
   pthread_t tid=pthread_self();
   printf("Estoy en el Thread %u y  proceso %u\n",tid,getpid());
}


void * function2(void *arg)
{
   pthread_t tid=pthread_self();
   printf("Estoy en el thread %u y proceso %u\n",tid,getpid());
}

int main()
{
   void *status;
   pthread_t tid1,tid2;
   pthread_attr_t attr;

    if(pthread_create(&tid1,NULL,function1,NULL)){
        perror("Failure");
        exit(1);
   }

   if(pthread_create(&tid2,NULL,function2,NULL)){
       perror("Failure");
       exit(2);
   }

   pthread_join(tid1,NULL);
   pthread_join(tid2,NULL);
   printf("Estoy en el thread principal %u y proceso %u\n",pthread_self(),getpid());
}

Ahora supongamos que el archivo que ustedes crearon tiene por nombre thread_kernel.c, en la consola lo compilamos de la siguiente forma:

 gcc thread_kernel.c -lpthread 

Una vez compilado al ejecutar no arroja los siguientes mensajes por pantalla:

./a.out 
Estoy en el thread 3152836352 y proceso 4553
Estoy en el thread 3161229056 y proceso 4553
Estoy en el thread principal 3169322752 y proceso 4553


Analicemos un poco este resultado, ¿Por que arroja el mismo PID de proceso para ejecuciones que tienen hilos de kernel distintos? Esto se debe a que getpid() (el cuál devuelve el id del proceso), da el mismo ID para todos los procesos, ya que en el estandar POSIX dice que la función debe devolver el mismo PID por que supone que todos se ejecutan bajo un mismo proceso. Es por ello, que linux introdujo un campo TGID(thread group Leader ID). Como vemos en pantalla el TGID es el mismo en el thread principal que el primer Thread que se crea, no así con el segundo, que usa un thread distinto de kernel.


Modelo Dos Niveles

Este modelo,también es parte del modelo muchos a muchos, con la salvedad que permite que un proceso tenga un thread de kernel directo como se aprecia en la imagen.

Modelo de 2 niveles.

En la práctica puede hacer lo siguiente:

  • Permite la combinación del modelo uno-uno y el modelo muchos a muchos.
  • Soporta threads dependientes y threads independientes.


La combinación de uno-a-uno + "estrictas" de muchos a muchos modelos Soporta ambos hilos dependientes e independientes:

** Threads dependientes : Es asignado de manera permanente a un solo LWP.
** Threads independientes: se pueden mover entre procesos lijeros en conjunto 

La creación, sincronización y programación de threads se lleva a cabo en el espacio de usuario.

Esto da un enfoque flexibe, ya que rescata lo mejor de ambos modelos.

Se usa principalmente en solaris, en la implementación de Pthreads[2] ( libreria para crear threads), aunque solo desde la versión 8 hacía atrás, desde la 9, este modelo debe ser definido explicitamente.

Este tipo de modelo también es usado en otras distribuciones UNIX,tales como IRIX[3] el cuál es un SO para la máquina MIPS y HP-UX[4], Siendo este último una aplicación para procesadores RISC´s.

Sección Investigación

Librerias más usadas en los distintos lenguajes

Referencias

Linux Kernel Support for Threads

Herramientas personales
Espacios de nombres
Variantes
Acciones
Navegación
Herramientas