Threads en el minikernel

Práctica de carácter optativo. El desarrollo satisfactorio de la misma puede proporcionar un punto más en la nota total. Sólo se podrá realizar esta práctica una vez que se ha completado satisfactoriamente la práctica obligatoria. La funcionalidad que se plantea en esta práctica se puede incluir en la versión obligatoria de la práctica o, si ya se ha desarrollado otra práctica optativa, puede juntarse con esta, aunque no obligatoriamente. Idealmente, un alumno podría desarrollar una única versión de la práctica que incluyera toda la funcionalidad planteada en los distintos enunciados.

Descripción de la funcionalidad pedida

Una de las principales dificultades que encuentra el alumno al enfrentarse con el concepto de thread es conseguir distinguir esta nueva entidad del concepto de proceso convencional. Generalmente, al alumno le resulta difícil saber qué información comparten los threads del mismo proceso y cuál es específica de cada thread. El objetivo es que el alumno pueda resolver de forma práctica estas dudas y, para ello, nada mejor que tener que implementar desde cero un esquema de threads sobre un sistema inicial que no los proporciona, como ocurre en la versión inicial del minikernel.

La inclusión de threads en el minikernel sólo requiere incluir una nueva llamada al sistema, “crear_thread”, con las siguientes características:

  • “int crear_thread(void *dir_funcion)”. Crea un flujo de ejecución que ejecuta la rutina que empieza en la dirección “dir_funcion”. Devuelve 0 si no hay error y -1 en caso contrario (por ejemplo, si se ha alcanzado el número máximo de threads en el sistema).

No va a existir una primitiva específica para terminar un thread, sino que, por simplicidad, va a usarse la primitiva “terminar_proceso”. El nuevo significado de esta primitiva es el siguiente:

  • El sistema operativo llevará la cuenta del número de threads que tiene cada proceso (como mínimo 1, el flujo implícito que se crea al llamar a “crear_proceso”).
  • Cuando el sistema operativo recibe una llamada “terminar_proceso”, termina la ejecución del thread actual y decrementa el número de threads del proceso. Si este valor llega a cero, el proceso completo termina.
  • No es necesario que una función que va a ser ejecutada desde un thread incluya al final un “terminar_proceso” ya que el entorno de apoyo se encarga de incluirlo automáticamente.

Un ejemplo del uso de estas primitivas sería el siguiente:

#include "servicios.h"
 
int f(){
    .......
}
 
inf g(){
    .......
    terminar_proceso(); /* no es necesario incluirlo */
}
 
int main(){
    .......
    crear_thread(f);
    .......
    crear_thread(g);
    .......
}

Algunos aspectos que hay que tener en cuenta a la hora de incluir threads son los siguientes:

  • Hay que diseñar las estructuras de datos adecuadas para crear esta nueva abstracción. Un posible diseño sería el siguiente:
    • Definir, además del vector de BCPs, un vector de threads (un vector de descriptores de thread, BCT) con un tamaño máximo “MAX_THREADS” (por ejemplo, 32) que almacenará la información de todos los threads existentes en el sistema.
    • Si se considera necesario, los threads de un mismo proceso podrían estar enlazados en una lista apuntada desde el BCP.
    • El BCT debe incluir una referencia al BCP correspondiente para poder acceder a información global del proceso.
    • Será necesario determinar qué aspectos están vinculados al proceso (almacenados en el BCP) y cuáles están relacionados con un thread (almacenados en el BCT).
  • El planificador pasa de planificar procesos a threads. Todas las listas de planificación (lista de listos, listas de bloqueados, etc.) son ahora listas de BCTs en vez de BCPs.
  • Es importante que se preste atención a la diferencia que hay entre crear el primer thread de un proceso, que se crea implícitamente dentro de “crear_proceso”, y crear los sucesivos threads del mismo, que se hará en la llamada “crear_thread”.
  • Con respecto a la llamada “tiempos_proceso”, hay que aclarar que la contabilidad de tiempos se refiere al proceso en su totalidad, y no a sus threads individuales.
  • Por lo que se refiere a la gestión de mutex, surgen diferencias dado que varios threads de un proceso pueden estar trabajando con el mismo mutex. Así, en “cerrar_mutex”, si el mutex está bloqueado lo desbloquea, pero sólo lo cierra si ningún otro thread del proceso lo está usando, devolviendo en ese caso un error.
  • Asimismo, hay que revisar la función “crear_mutex”, de manera que, aunque se siga comprobando que no se ha excedido el número máximo por proceso (si es así, hay un error), cuando un proceso se bloquea en esta llamada, no se considere que ha gastado un descriptor, teniendo que volver a comprobarlo al desbloquearse.
  • Cuando se produzca una excepción, siguiendo el modo de operación de la mayoría de las implementaciones de threads, se terminará la ejecución de todo el proceso al que pertenece el thread que causó la excepción, o sea, de todos los threads de dicho proceso, puesto que se trata de un error de programación.

Como se estudia en la teoría de la asignatura, la terminación involuntaria es una operación delicada, que se analiza en detalle en el enunciado de la práctica optativa del manejador de terminal. El análisis presentado en esa sección es aplicable a esta práctica trasladándolo desde procesos convencionales hasta threads.

Código fuente de apoyo

Para la realización de esta práctica se tomará como base el código desarrollado en la práctica obligatoria del minikernel. Para poder trabajar en esta práctica sin afectar al código de la parte obligatoria y poderla entregar de manera independiente, se debe copiar a un nuevo directorio denominado “minikernel_thread.2016”. Desde el directorio base del usuario, se pueden ejecutar los siguientes mandatos para realizar esta copia:

$ mkdir DATSI/SOA/minikernel_thread.2016
$ cp -R DATSI/SOA/minikernel.2016/* DATSI/SOA/minikernel_thread.2016

Entrega del código y documentación

El mandato a ejecutar es:

entrega.soa minikernel_thread.2016

Este mandato realizará la recolección de los mismos ficheros que en la práctica obligatoria del minikernel.

No existe un corrector automático para esta práctica. El alumno deberá usar sus propios programas de prueba.

Las prácticas entregadas serán corregidas una vez terminado el plazo de entrega, que es el mismo de las prácticas obligatorias.

 
docencia/asignaturas/soa/practicas/minikernel_thread.txt · Última modificación: 2017/01/30 12:08 por fperez
 
Recent changes RSS feed Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki