20
Tema 4 Procesadores y procesos en sistemas distribuidos Es posible disponer en un proceso de más de un flujo de ejecución. A cada uno de estos flujos le denominaremos "thread". La introducción de threads en la codificación de servidores aporta ventajas e inconvenientes que serán estudiados en primer lugar. Por otra parte, en un sistema distribuido se dispone de más de un procesador. A continuación, estudiaremos las diversas formas de organizar los procesadores. Finalmente, estudiaremos la forma de asignar un proceso entre todos los procesadores disponibles. 4.1 Procesos y threads En los años ochenta se descubrió que el concepto de proceso, tal como lo entendemos en el mundo UNIX, resultaba desproporcionado para los requisitos de los sistemas distribuidos. El problema radica en que UNIX asocia un único thread de control con cada proceso. Un proceso es un recurso costoso en su creación y en su gestión. Ello lleva consigo que la cooperación entre las distintas actividades de una aplicación donde cada una de ellas ha sido implementada como un proceso sea difícil de programar y costosa en términos de ciclos de UCP por el gran número de llamadas al sistema requeridas en la comunicación de actividades comunicación de procesosy en la planificación de las mismas cambios de contexto(Fig. 4.1). Fig. 4.1 Mapeo tradicional de actividad como proceso En la actualidad, la investigación en sistemas distribuidos y el concepto de microkernel han puesto de manifiesto la necesidad de que en un mismo espacio de direccionamiento convivan más de un thread de control. Aunque no es la única, una de las finalidades de los threads es mejorar las prestaciones de los

[03] Sistemas Distribuidos - Procesadores y Procesos

Embed Size (px)

DESCRIPTION

Por otra parte, en un sistema distribuido se dispone de más de un procesador. A continuación, estudiaremos las diversas formas de organizar los procesadores. Finalmente, estudiaremos la forma de asignar un proceso entre todos los procesadores disponibles.

Citation preview

Page 1: [03] Sistemas Distribuidos - Procesadores y Procesos

 

 

Tema  4  

Procesadores y procesos en sistemas distribuidos 

Es posible disponer en un proceso de más de un flujo de ejecución. A cada uno de estos flujos le denominaremos "thread". La introducción de threads en la codificación de servidores aporta ventajas e inconvenientes que serán estudiados en primer  lugar. Por otra parte, en un  sistema distribuido  se dispone de más de un procesador. A continuación, estudiaremos las diversas formas de organizar los procesadores. Finalmente, estudiaremos la forma de asignar un proceso entre todos los procesadores disponibles. 

4.1 Procesos y threads En  los años ochenta  se descubrió que el concepto de proceso,  tal como  lo entendemos en el mundo UNIX, resultaba desproporcionado para los requisitos de los sistemas distribuidos. El problema radica en que UNIX asocia un único thread de control con cada proceso. Un proceso es un recurso costoso en su creación y en su gestión. Ello lleva consigo que la cooperación entre las distintas actividades de una apli‐cación donde cada una de ellas ha sido implementada como un proceso sea difícil de programar y costo‐sa en términos de ciclos de UCP por el gran número de llamadas al sistema requeridas en la comunica‐ción de actividades ‐comunicación de procesos‐ y en la planificación de las mismas ‐cambios de contexto‐ (Fig. 4.1). 

 

Fig. 4.1  Mapeo tradicional de actividad como proceso 

En  la actualidad,  la  investigación en sistemas distribuidos y el concepto de microkernel han puesto de manifiesto la necesidad de que en un mismo espacio de direccionamiento convivan más de un thread de control. Aunque no es  la única, una de  las finalidades de  los threads es mejorar  las prestaciones de  los 

Page 2: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

 

servidores, ahora no ocultos en las profundidades del sistema sino construidos como procesos de usua‐rio. En esta sección discutimos el concepto de thread y sus implicaciones. 

4.1.1 Introducción al concepto de thread 

En ocasiones, el servidor de ficheros debe bloquearse porque los octetos que solicita un proceso de usua‐rio no se encuentran en la caché y debe solicitar la lectura del bloque correspondiente al manejador de disco. El servidor de ficheros se bloquea esperando el servicio. Leer un bloque de disco lleva algún tiem‐po. Durante este tiempo, el manejador se también se bloquea. El resultado del bloqueo del servidor es que otras peticiones de bloques por parte de otros procesos de usuario no pueden ser atendidas, estén o no estén los octetos solicitados disponibles en la caché. Para subsanar el problema se debe disponer de uno o más threads alternativos en el servidor de ficheros que continúen con la ejecución. Así, cuando un thread se bloquea en la solicitud de un bloque al manejador de disco duro, otro thread toma el control sirviendo  la siguiente petición, cuyos octetos pueden estar en  la caché. La  introdución del concepto de thread aumenta la concurrencia y las prestaciones del servidor de ficheros. 

Puede pensarse que la concurrencia puede también lograrse mediante réplicas del servidor de ficheros. Cada réplica puede atender una solicitud de la aplicación de usuario. Esta es una opción que no da resul‐tado porque, entre otras cosas, ambos procesos necesitan compartir  la caché de bloques. Ello exige un proceso dedicado a soportar la caché y mecanismos de paso de mensajes entre los dos servidores (Fig. 4.2), una opción ineficiente debido a los costos de comunicación. 

 

Fig. 4.2  Aceleración del servidor de ficheros por replicación 

El uso de threads es la mejor opción. La figura 4.3 a) muestra tres procesos. Cada uno de ellos tiene su propio espacio de direccionamiento y descriptor de proceso. Los tres procesos, ya que no comparten es‐pacio de direcciones, deben  comunicarse haciendo uso de  los  servicios de  comunicación de procesos ofrecidos por el sistema operativo. En la figura 4.3 b) observamos un único proceso con tres threads de control. Cada uno de ellos tiene su propio contador de programa y su propia pila, pero todos ellos com‐parten el mismo espacio de direcciones. A estos mini‐procesos se les denomina threads o procesos lige‐ros. Por supuesto, los threads comparten la UCP en un sistema monoprocesador. En un hardware multi‐procesador, sin embargo, los threads pueden ejecutar en paralelo. Un thread puede crear un thread hijo y, al igual que los procesos invocar, llamadas al sistema. Si un thread se bloquea en una de estas llamadas, otra puede tomar la UCP sin que el sistema operativo necesite cambiar de contexto. 

Page 3: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

 

  

Fig. 4.3  a) Tres procesos con un thread de control cada uno.  

b) Un proceso con tres threads de control. 

Los threads comparten un mismo espacio de direccionamiento, de modo que no hay protección entre ellas, todas tienen acceso a las varibles globales del resto. El hecho es que proporcionar protección entre los threads, primero, es  imposible y, segundo, no es necesario. A diferencia de los procesos de usuario, los threads son programados por un mismo programador, de modo que no deben intentar acciones per‐judiciales para el resto de los threads sino todo lo contrario y, si lo hacen debido a un error de codifica‐ción, la responsabilidad recae sobre el programador. Además de compartir espacio de direccionamiento, los threads comparten los mismos ficheros abiertos, manejadores de señal, procesos hijos, etc, algo que es útil cuando los threads no son independientes, sino que colaboran en un fin común. 

4.1.2 El Contexto de un thread La figura 4.4 muestra un programa que calcula dos valores y los suma. La figura 4.5 muestra el proceso tradicional UNIX asociado al programa con el contexto del proceso determinado por tres bloques dis‐tintos, los registros, la identidad del proceso y los recursos. 

int r_a, r_b; main() { calcula_a(&r_a); calcula_b(&r_b); reune(r_a, r_b); } void calcula_a(int *res) { ... *res = Cálculo_a(); } void calcula_b(int *res) { ... *res = Cálculo_b(); } void reune(int p, int q) { printf("%d\n", p+q); }

Fig. 4.4  Programa 

máquina B

procesos

máquina A

threadscontador de programa

Page 4: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

 

Fig. 4.5  El proceso de la Fig. 4.4 y su contexto 

Los cálculos de los valores r_a y r_b son dos actividades paralelas, de modo que cada una puede ser soportada por un thread, según ilustra la Fig. 4.6. Cada thread tiene su propia pila. Como se aprecia el contexto de un thread es mucho más ligero que el contexto de un proceso. 

Fig. 4.6  El proceso de la Fig. 4.4 con dos threads de control 

4.1.3 ¿Dónde se usan los threads? Los threads fueron inventados a fin de combinar el paralelismo con la ejecución secuencial y las llamadas al sistema bloqueantes. Supongamos la organización de threads de la figura 4.7. En ella tenemos un thre‐ad denominado el despachador  junto a un conjunto de  threads denominados  trabajadores. Todos  los threads, despachador y  trabajadores, ejecutan bajo  la supervisión de una rutina del "núcleo de ejecu‐ción" denominada el planificador. Vamos a suponer que un trabajador espera órdenes del despachador bloqueado en un semáforo. Supongamos que el despachador se bloquea esperando una petición de ser‐vicio de  los procesos de usuario. Cuando el despachador recibe  la solicitud de servicio  ‐por ejemplo,  la lectura de un bloque de disco‐, elige un trabajador ocioso, copia el mensaje en sus variables y lo despier‐ta mediante una operación sobre el semáforo. Hecho esto, el despachador vuelve a esperar un mensaje 

Page 5: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

 

de  los procesos de usuario. El  trabajador  toma el control mientras el despachador espera, examina el mensaje y determina si el bloque solicitado se encuentra en la caché. Si no es así, envía un mensaje a la tarea del disco y espera bloqueado la réplica de ésta. Este bloqueo causará la ejecución del planificador, que dará paso a otro thread, posiblemente el despachador que ahora está dispuesto debido a la llegada de una nueva solicitud de acceso al disco, o posiblemente otro trabajador, que ahora está dispuesto para tomar la UCP.  

 

Fig. 4.7  Un servidor con threads 

Consideremos  lo que ocurre si el servidor de ficheros ha sido  implementado como un proceso conven‐cional, es decir, con un solo thread de control. Un servidor de este tipo está escrito como un blucle infini‐to de espera de petición y servicio. Tras recibir una petición, la sirve antes de ponerse a esperar la próxi‐ma. Si  los datos están en  la caché,  la petición se sirve de  inmediato, pero si no es así, debe  iniciar una transferencia de disco y esperar a que ésta concluya. En este  intervalo de tiempo  las nuevas peticiones que se incorporan no pueden ser atendidas porque están retenidas. Pudiera ser que llegasen dos peticio‐nes con los bloques en la caché. Si el servidor tuviese dos threads de control, mientras uno espera al dis‐co, el otro podría servir estas dos peticiones. La conclusión es que con el mecanismo de threads, las pres‐taciones del servidor aumentan porque sirve más peticiones por unidad de tiempo. En un servidor sin threads, una petición que deba acceder al disco provoca el bloqueo del  sistema de  ficheros para que otros procesos tomen la UCP. Sin embargo, en muchas ocasiones el servidor de disco es una máquina de‐dicada a esta tarea, de modo que la UCP queda ociosa, por lo que el uso de threads queda más justifica‐do, si cabe. Como podemos apreciar, los threads proporcionan mayores prestaciones. 

Existe, no obstante, una forma de programar servidores sin utilizar threads que alcanza un alto grado de paralelismo. El servidor es concebido como una máquina de estado finito. Existe un único thread de con‐trol que espera las peticiones de los procesos de usuario. Cuando una petición puede ser servida a partir de la caché se sirve y se espera una nueva petición. Cuando el bloque no está en la caché es preciso en‐viar un mensaje al manejador del disco, grabando en una tabla el estado de la petición. Este mensaje se envía mediante una primitiva send no bloqueante, de modo que registramos la situación de la llamada pendiente y regresamos a esperar una nueva petición de los procesos de usuario. En este momento pue‐den llegar dos tipos de mensajes de naturaleza diferente, según indica la Fig. 4.8.  Uno, una petición de usuario y, dos, una réplica del manejador de disco. En este diseño, el modelo de "proceso secuencial" se ha perdido en favor de una autómata finito que reacciona y modifica su estado interno en función de los mensajes que recibe. 

Page 6: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

 

 

Fig. 4.8  Un servidor como máquina de estado finito 

Frente al modelo del autómata, con llamadas no bloqueantes, la ventaja de los threads es que aumentan el paralelismo mientras son programadas haciendo uso de primitivas bloqueantes. El paralelismo aporta prestaciones y las llamadas bloqueantes sencillez en la programación. Cuando un thread solicita un blo‐que al disco, esta petición puede realizarse mediante una primitiva bloqueante como sendrec o me‐diante una  llamada RPC, tal y como se hace en  la programación convencional. No es preciso  introducir primitivas send no bloqueantes que complican extraordinariamente la programación. Esta aportación de paralelismo más primitivas bloqueantes es la aportación del concepto de thread. La Tabla 4.1 resume los tres modelos. 

Modelo   Características

Threads  Paralelismo, llamadas bloqueantes

Proceso  NO paralelismo,  llamadas bloqueantes

Autómata finito  Paralelismo,  llamadas NO bloqueantes

Tabla 4.1  Tres formas de programar un servidor. 

Por otra parte,  los  threads  también pueden ser organizados en  forma de  tubería. Con este modelo, el primer thread genera un dato que pasa a otro thread para que lo procese. Con más de dos threads, los datos son procesados y entregados al siguiente thread de forma sucesiva. Este modelo no es apropiado para  la construcción de servidores, pero sí cuando se presenta el problema de  los  lectores y escritores. Los threads permiten resolverlo en un proceso único. El modelo de tubería se emplea también en la es‐critura de clientes. La figura 4.9 muestra un cliente con dos threads. El primer thread genera resultados que deben ser almacenados en un servidor mediante una llamada RPC. Desafortunadamente, una llama‐da convencional RPC es bloqueante, lo que hace esperar al cliente. Para evitarlo, el cliente puede incor‐porar un segundo thread, que realiza la llamada RPC. Mientras el segundo thread permanece bloqueado, el primero puede seguir generando nuevos resultados. Ambos threads comparten una estructura de da‐tos en la que actúan como escritor y lector respectivamente. 

Page 7: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

 

 

Fig. 4.9  Cliente con threads 

Otro uso de los threads es dedicar uno de ellos a la ejecución de un manejador de señal, como el especi‐ficado en la llamada UNIX signal(Nro_Señal, Manejador). Cuando una señal llega al proceso, por ejemplo el vencimiento de una alarma (SIGALRM) o la pulsación de Ctrl‐C en el teclado (SIGINT), se activa el thread que las sirve, hasta ese momento bloqueado, como alternativa a la ejecución del ma‐nejador. Este esquema evita la progamación del manejador por el usuario, pero debe programar el thre‐ad asociado. 

Finalmente, en computadores multiprocesador, cada thread puede ser asignado a un procesador, de mo‐do que el proceso puede ejecutar en paralelo. En un computador de una sóla UCP no es posible, pero la programación de la aplicación es independiente de este hecho.  

4.1.4 Implementando un paquete de threads Hay dos formas de implementar una biblioteca de threads. Una en espacio del núcleo. Dos, en espacio de usuario. La elección está actualmente sujeta a controversia y una implementación híbrida también es po‐sible. En esta sección describimos ambos métodos, mostrando sus ventajas e inconvenientes. 

4.1.4.1 Implementación de threads en espacio de usuario El primer método de implementación de threads consiste en gestionarlos enteramente en el proceso de usuario, de modo que el núcleo del sistema operativo no sepa nada acerca de si el proceso tiene un thre‐ad de control o más de uno. La ventaja más obvia de los threads en espacio de usuario es que podemos disponer de ellos sin tener que modificar nuestro sistema operativo. De hecho, varias bibliotecas de thre‐ads han sido desarrolladas para UNIX, que tradicionalmente no soporta threads. 

Todas la implementaciones de threads en espacio de usuario tienen la estructura de la figura 4.10 a). Los threads ejecutan solicitando servicios del "núcleo de ejecución", un módulo de procedimientos para ges‐tionar y planificar los threads. Cuando un thread ejecuta una acción que exija su suspensión, opere sobre un mutex, invoque una llamada al sistema o cualquier cosa que provoque el bloqueo, llama a un proce‐dimiento del núcleo de ejecución. Este procedimiento comprueba si el thread debe ser suspendido y, en ese caso, almacena los registros del thread en una tabla, busca un thread dispuesto y lo pone a ejecutar. Un cambio de contexto de threads es al menos un orden de magnitud menos costoso que un cambio de contexto ordinario, donde el núcleo debe realizar mucho más trabajo. Una conmutación de thread exige poco más que cambiar los registros del procesador, entre ellos el contador de programa y el puntero de pila. Esta velocidad en la conmutación de contexto es el argumento más fuerte en favor de realizar la ges‐tión de threads mediante una biblioteca de usuario. 

Page 8: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

 

  

Fig. 4.10  a) Biblioteca de gestión de threads en espacio de usuario.  

b) Threads gestinados por el núcleo. 

Otra de las ventajas de las bibliotecas de threads es que permite a cada proceso escoger su propio algo‐ritmo de planificación de threads. Ciertos threads requieren que el algoritmo no sea expulsor a fin de no ser interrumpido en un momento inoportuno. Otra de las ventajas es que las bibliotecas de threads per‐miten más threads en el sistema que si los threads son gestionados por el sistema operativo. Cada thread requiere espacio en el sistema operativo para mantener su gestión y este espacio tiene un  límite, algo que no ocurre con los threads de usuario, donde el número de threads por proceso puede ser muy gran‐de, así como el número de procesos con threads. 

A pesar de ser más rápidos que los threads soportados por el núcleo, las bibliotecas de gestión de thre‐ads acusan serios problemas estructurales. El primero de ellos es: ¿Cómo se implementan las llamadas al sistema bloqueantes? Permitir que un thread realice una llamada al sistema que bloquee el proceso, co‐mo leer de una tubería vacía es inaceptable, ya que todos los threads se ven afectados por el necesario cambio de contexto del proceso. Ya vimos que una de las metas de los threads era la programación con primitivas bloqueantes manteniendo el paralelismo entre los threads. Si un thread emite una llamada al sistema bloqueante el paralelismo se quiebra. La solución es cambiar las llamadas al sistema bloqueantes por otras no bloqueantes. Sin embargo, esto requiere cambiar el sistema operativo, desde luego algo po‐co atractivo. Además, una de las hipótesis de trabajo del soporte de threads en el proceso de usuario era que esta ejecutase sobre la plataforma de trabajo habitual, sin introducir en el sistema operativo modifi‐cación alguna. Cambios en los servicios que presta el sistema conlleva cambios en la mayoría de las apli‐caciones, lo que es absolutamente indeseable. 

Una alternativa a la modificación de los servicios bloqueantes por otros no bloqueantes es posible si tu‐viésemos un mecanismo que informase acerca de si una llamada al sistema va a bloquearse o no. En al‐gunas versiones de UNIX existe la llamada al sistema select. Esta llamada permite conocer al proceso de usuario que la invoca si una tubería está vacía o si no lo está, entre otras cosas. La definición de la lla‐mada select es la siguiente: 

select(int maxfdp1, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout );  

Page 9: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

 

Los argumentos readfs y writefs son un puntero a un bloque de enteros. Si el bloque tiene cuatro enteros de 32 bits, podemos identificar 32*4=128 descriptores de proceso en el bloque, aquellos cuyo bit esté activo. El primer entero del bloque identifica los descriptores 0 a 31, el segundo los descriptores 32 a 63, etc. El nombre mismo de la llamada deriva del descriptor o los descriptores en los que estamos inte‐resados. Los descriptores en readfs y writefs son comprobados por el núcleo, que decide si están listos para lectura (ha llegado algún dato) o están listos para escritura (se puede seguir enviando datos). La estructura timeval tiene un campos, uno son segundos y otro microsegundos. Si ambos campos son 

nulos, select retorna en readfs y writefs los descriptores preparados para lectura o escritura. Si el plazo especificado es distinto de cero, select suspende el proceso y retorna cuando el plazo vence.  

En cuanto a la programación de threads, select puede ser invocada, por ejemplo, para determinar si una tubería está vacía, es decir, si está preparada para lectura. Si está vacía, select retorna indicando esta situación, de modo que el thread no realiza una llamada de lectura sobre la misma a fin de no blo‐quear el proceso completo y, por  lo tanto, retrasar el resto de  los threads. Alternativamente, el thread puede dar paso a otro thread mediante una llamada al planificador local para que ejecute otro thread. El método de select  supone prohibir  a  los  threads  invocar  las  llamadas  al  sistema bloqueantes.  Para éstas se construye un biblioteca especial, donde se comprueba si va a producirse el bloqueo y, en tal ca‐so, dar paso al planificador. Este código de comprobación que encapsula la llamada al sistema se deno‐mina chaqueta. La chaqueta es una opción poco elegante y poco eficiente, ya que, al menos, dobla el número de llamadas al sistema que hacen los threads. 

La  rutina que sirve  las  interrupciones del  reloj  reside en espacio del núcleo. Los procesos solicitan del núcleo servicios de temporización, pero desconocen cuando se produce un pulso de reloj. Como conse‐cuencia, el planificador de threads en el núcleo de ejecución es incapaz de determinar cuándo un thread ha ejecutado durante demasiado  tiempo. Consecuentemente, es  la  tarea  la que debe  invocar volunta‐riamente al planificador cuando ha ejecutado durante demasiado tiempo. Por otra parte, un problema se codifica con threads cuando conceptualmente tiene tareas claramente  independientes que pueden ser programadas como threads. Las tareas se comunican entre sí o solicitan servicios de entrada‐salida. En cualquiera de los dos casos, deben dar paso al planificador, que entonces toma el control y puede planifi‐car otro thread. Por lo tanto, el planificador, si bien no se activa periódicamente como la rutina de inte‐rrupción de reloj, es invocado muy a menudo por los threads que gestiona. Si los threads raramente invo‐can al planificador deberíamos cuestionarnos si  la  forma más adecuada de codificar nuestro problema son los threads y no un proceso clásico de un único flujo de control. 

A pesar de todo, la ausencia de un reloj en el planificador de threads trae sus consecuencias negativas. Por ejemplo, la espera activa en un thread esperando que otro thread abra un cerrojo está prohibida, ya que el thread que lo abre nunca toma la UCP y, como consecuencia, la espera activa se hace infinita. Una posible solución es que el planificador de threads requiera una interrupción de reloj cada cierto tiempo, por ejempo un segundo. Esta opción exige incorporar a la programación del planificador el manejo de ex‐cepciones  ‐señales en C‐,  algo que  la  complica notablemente. Por otra parte,  requerir un  servicio de alarma muy preciso, con un periodos de pocos milisegundos  resulta caro para el núcleo y  la precisión suele ser escasa en nucleos convencionales. Hay otra razón que juega en contra de esta solución y es que la alarma del planificador suele colisionar con las alarmas solicitadas por los threads. En el lenguaje C, la alarma y, en general, todas las señales, son conceptos asociados al proceso, no al thread. 

4.1.4.2 Implementación de threads en el núcleo Si el núcleo es consciente de los threads de los procesos, el núcleo de ejecución del proceso de usuario que gestiona los threads desaparece, como indica la figura 4.10 b). Cuando un thread quiere crear otro 

Page 10: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

10 

 

thread o destruirlo,  invoca una  llamada al sistema. El descriptor de proceso en el núcleo crece. Ahora también debe incluir una tabla de descriptores de threads, con una entrada por thread. La misma infor‐mación que mantenía el núcleo de ejecución ahora se traslada al descriptor de proceso en el núcleo. 

En ausencia del núcleo de ejecución, todas las llamadas que pueden bloquear el thread como por ejem‐plo las de sincronización como subir un semáforo, son implementadas como llamadas al sistema. Enton‐ces el núcleo puede activar un thread bien del mismo proceso o bien de otro. La principal desventaja es el costo de las llamadas de creación, terminación, sincronización, etc, ya que todas ellas exigen un cambio de contexto. 

Las ventajas de los threads gestionados en el núcleo estriban en que no requieren vesiones no bloquean‐tes de las llamadas al sistema y, por lo tanto, su programación es más sencilla. Además, si un thread oca‐siona un fallo de página, el núcleo puede activar otro thread del mismo proceso mientras llega la página. 

Hemos visto problemas específicos que afectan unos a la implementación en espacio de usuario y otros a la  implementación en el núcleo. Además, existen problemas que atañen a ambos. Uno de ellos es que muchos procedimientos de biblioteca no son reentrantes. El uso de threads hace que un thread invoque al procedimiento y, en mitad de un acceso a una estructura de datos global, se otorga la UCP a otro thre‐ad. Este thread pude perfectamente  invocar a este mismo procedimiento. La estrutura a  la que accede seguramente se encuentra en un estado  inconsistente. Uno de estos procedimientos es malloc, de  la biblioteca estándar del lenguaje C. Este procedimiento accede a tablas globales delicadas. No ha sido es‐crito pensando en que puede ser invocado por threads distintos, de modo que no es reentrante. Un caso parecido es la variable global errno. La biblioteca estándar C debe ser reescrita en gran parte cuando se utilizan  threads.  Este problema  se  soluciona  envolviendo  cada procedimiento de  la biblioteca  en una chaqueta que consiste en un mutex global a toda la biblioteca, que convierte esta en un monitor gigan‐tesco. 

También es problemático el tratamiento de señales, ya que cada thread puede desear un manejador par‐ticular para una señal dada. En el lenguaje C los manejadores se establecen mediante la llamada al siste‐ma signal(Nro_Señal, manejador); El último manejador activado es el vigente, sustituyendo al previamente activado, tal vez por otro thread o por el núcleo de ejecución. 

4.1.4.3 El concepto de "Activación del planificador" De la discusión mantenida acerca de dónde implementar los threads, bien en el núcleo, bien en espacio de usuario, se llega a la conclusión de que, dado el estado de conocimiento actual, ninguna es mejor que la otra. Varios investigadores han tratado de conciliar una y otra aproximación. En esta línea, vamos a es‐tudiar un tipo de implementación híbrida de threads, propuesta por Anderson en el año 1991, basado en el concepto de "activación del planificador". 

Esta implementación particular busca la eficiencia y flexibilidad de los threads de usuario y la funcionali‐dad de los threads en el núcleo. En primer lugar, las llamadas al sistema no bloqueantes o de comproba‐ción de bloqueo no se utilizan. Sólo se usan llamadas al sistema bloqueantes. Sin embargo, las llamadas al sistema bloqueantes deben invocarse lo menos posible. Por ejemplo, si un thread debe sincronizarse con otro thread del mismo proceso, debe realizarse mediante un semáforo local que mantiene el planificador de threads local que muestra la figura 4.10 a), sin que sea preciso invocar una llamada al sistema. A pesar de todo, en ocasiones como el acceso al disco, es preciso realizar una llamada bloqueante. En este caso, o bien en el caso de un trap por falta de página en la ejecución de un thread, el núcleo toma el control. Su labor ahora es invocar al servidor pertinente y comunicar el bloqueo del thread a su núcleo de ejecución. De aquí el nombre de "activación del planificador". Esta comunicación se denomina upcall.  

Page 11: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

11 

 

¿Cómo se implementa un upcall? El mecanismo es el mismo que utiliza un núcleo UNIX para comunicar una señal a un proceso de usuario. Este mecanismo es, grosso modo, el siguiente. El núcleo conoce la di‐rección de comienzo del núcleo de ejecución y el puntero de pila del proceso. En la pila del proceso colo‐ca lo que se denomina una activación, a saber, una serie de bytes con información a cerca de la identidad del thread bloqueado y el tipo de evento acontecido por una parte y, por otra, en el campo del descriptor de proceso que guarda el contador de programa, escribe la dirección de comienzo de un procedimiento del núcleo de ejecución. Tras esto, da UCP a este proceso o bien a otro distinto. En cualquier caso, cuando el proceso tome la UCP, será el procedimiento del núcleo de ejecución el que ejecute y no el thread que hizo la llamada bloqueante. Los parámetros de este procedimiento están en la pila, de modo que entien‐de que el thread cuyo identificador es uno de sus parámetros está bloqueado en una llamada al sistema y, por lo tanto, puede tomar la decisión de activar otro thread de entre los threads dispuestos. 

Como acabamos de ver en el párrafo anterior, el planificador actúa sobre los threads cada vez que uno de ellos hace una llamada al sistema. De esta forma, si los threads realizan llamadas al sistema con una fre‐cuencia razonable, el planificador tiene muchas ocasiones de ser invocado y activar los threads que con‐sidere oportunos de acuerdo a su algoritmo particular. No hay necesidad que sea activado periódicamen‐te por el núcleo a instancias del manejador de reloj. 

4.2 Modelos De Sistemas Un sistema distribuido se caracteriza, entre otras cosas, porque dispone de más de un procesador. En es‐ta sección nos ocupamos de cómo organizar los procesadores. Examinaremos dos modelos, el modelo de estación de trabajo y el de fondo de procesadores. 

4.2.1 El modelo de estación de trabajo Consiste en un conjunto de estaciones de trabajo conectadas mediante una red  local. En un momento dado, una estación de trabajo está ocupada o bien no está siendo utilizada por ningún usuario. Decimos entonces que está ociosa. Algunas estaciones de trabajo tienen disco y otras no tienen disco. Estas últi‐mas conservan sus ficheros en el disco de otras estaciones, en las que ejecuta un servidor de ficheros. El servidor es accedido a través de la red local.  

Las ventajas del modelo de estaciones de trabajo son varias. Por una parte, cada usuario tiene una po‐tencia de cálculo dedicada a él en exclusiva,  lo que garantiza el tiempo de respuesta. Es posible utilizar aplicaciones gráficas sofisticadas, ya que tienen acceso directo a un hardware gráfico de altas prestacio‐nes. Cada usuario tiene plena autonomía, de modo que puede utilizar los recursos de su máquina según su propio criterio. El modelo también presenta inconvenientes. Uno de ellos es el descenso continuado de los precios de los procesadores. Pronto será económicamenta factible el que cada usuario disponga de diez UCP, e incluso cien. La pena es que deba adquirir cien estaciones de trabajo para aprovechar el pre‐cio del hardware. El otro es el de las estaciones de trabajo ociosas, ya que su potencia de cálculo es des‐aprovechada. Los recursos de cómputo no están bien gestionados. En ocasiones, algunos usuarios necesi‐tan una estación más potente para ciertas aplicaciones mientras que si estas existen, tal vez estén ocio‐sas. El primer problema, sin embargo, no es tal, ya que se soluciona construyendo estaciones de trabajo multiprocesador. Por ejemplo, a cada procesador puede asignársele  los trabajos arrancados desde una ventana dada. 

Page 12: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

12 

 

4.2.2 Usando estaciones ociosas En las universidades este problema se acusa intensamente. En determinadas horas del día, casi todos los puestos de trabajo están ocupados y en ciertos periodos del año ‐que se ha observado coinciden con los plazos de entrega de prácticas‐ el número de puestos resulta claramente  insuficiente. En otras horas y otras fechas, el número de estaciones ociosas es notorio. Este despilfarro de recursos ha preocupado a los investigadores, que han propuesto esquemas diversos a fin de paliar esta situación. El primer intento conocido de sacarle partido a una estación ociosa fue el mandato UNIX BSD rsh (de shell remoto). Se in‐voca como 

  cc% rsh maquina mandato

El primer parámetro es la dirección de red ‐típicamente una dirección IP‐ de una estación de trabajo y el segundo parámetro es el mandato que se desea ejecutar. La salida del mandato se redirige al terminal de emisión del mandato. El defecto de rsh es que el mandato es ejecutado por un shell que en general proporciona un entorno al mandato distinto al entorno local. En segundo lugar, es el usuario el que debe buscar una máquina ociosa, tal vez esperando que el dueño se vaya a tomar el bocadillo. Un tercer pro‐blema es que cuando el usuario vuelve se encuentra con que la máquina va más lenta, lo que con seguri‐dad conduce a un cuarto problema, esta vez más acusado por el usuario que invocó rsh. 

La investigación en estaciones ociosas se ha centrado en la resolución de los siguientes problemas: 

1. ¿Cómo encontrar una estación ociosa? 2. ¿Cómo puede un proceso ejecutar transparentemente? 3. ¿Qué ocurre si el dueño de la máquina ociosa vuele? 

 Buscando una estación ociosa Comencemos por el primer problema. Cabe antes preguntarnos ¿qué es una estación ociosa? En apa‐riencia, es aquella sin un usuario cerca. Sin embargo, aun en tal caso, en un sistema actual ejecutan mu‐chos procesos en "background",  como puede ser el demonio de impresión, de correo, de transferencia de ficheros y otros mil demonios. De todas formas, se suele considerar como ociosa una máquina que no tiene activo ningún proceso de usuario y cuyo teclado o ratón no han sido tocados durante varios minu‐tos. Sea cual sea el critero para determinar cuándo una máquina está ociosa, los algoritmos para localizar una máquina ociosa son de dos tipos: servidores y clientes. Algoritmos servidores Se basan en un registro o base de datos de máquinas ociosas. Este registro se mantiene en una determi‐nada máquina. Cuando una estación decide que está ociosa se dice que se convierte en un servidor de computación. En este momento envía un mensaje a la máquina que mantiene el registro, donde se abre una nueva entrada con la dirección y características de la nueva máquina ociosa. Cuando en una estación determinada un usuario decide ejecutar un mandato en una máquina ociosa, invoca el mandato remo-te, al que pasa como argumento el nombre de la aplicación o mandato que desea ejecutar: 

cc% remote mandato

remote accede al registro para escoger una máquina apropiada. Este esquema se ilustra en la figura 4.11. 

Page 13: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

13 

 

 

Fig. 4.11  Un algoritmo basado en registro para encontrar y usar estaciones ociosas. 

 

Algoritmos cliente Cuando se  invoca remote,  se difunde una petición diciendo qué programa se desea ejecutar, cuánta memoria necesita, si requiere o no un procesador de coma flotante, etc. Si todas las máquinas son igua‐les, esta  información no es precisa, pero, en un entorno heterogéneo es esencial, por que no todos  los programas pueden ejecutar en todas  las máquinas. Cuando  las réplicas de  las máquinas ociosas  llegan, remote elige una de ellas para ejecutar allí el programa. Una modificación útil es aquella en que cada es‐tación ociosa retrasa el envío de la réplica en función de su carga de trabajo. La menos ocupada será la primera en enviar la réplica y será la máquina escogida. Ejecutando el programa en la máquina remota Encontrar una estación ociosa donde ejecutar un proceso es sólo el primer paso. La dificultad estriba en disponer en dicha máquina del mismo entorno de ejecución que en la máquina local (home workstation), de modo que el proceso ejecute de la misma forma en ambas. En la máquina remota, el proceso migrado necesita la misma vista del sistema de ficheros, el mismo directorio de trabajo y las mismas variables de entorno. Sólo después el proceso puede ejecutar. El problema que se plantea en una ejecución remota es el servicio de las llamadas al sistema. ¿Qué debe hacer el kernel, por ejemplo, para dar servicio a la llamada read? Depende de la arquitectura del siste‐ma. Si las máquinas no tienen disco, sino que confían en un servidor de disco, todas las lecturas son redi‐rigidas al  servidor de disco, de  la misma  forma que  se hubiese hecho en  la máquina  local. En el  lado opuesto,  si  todas  las máquinas  tienen disco,  la petición debe  ser  redirigida a  la máquina  local  (home workstation). Otras llamadas como sbrk, que realiza una modificación del tamaño del segmento de da‐tos del proceso, necesariamente deben ser servidas localmente. Lo mismo ocurre a llamadas que solici‐tan el estado de la máquina así como información acerca de la misma como su dirección de red, la me‐moria de que dispone, etc. 

Las llamadas al sistema que tratan con el tiempo son problemáticas por que las máquinas local y remota no están generalmente sincronizadas. Si usamos el tiempo de la estación remota puede introducir incon‐sistencias como vimos en el programa make. Si usamos el tiempo de  la máquina  local (home worksta‐tion) el retraso que provoca  la comunicación también es fuente de problemas. En fin, aunque ejecutar procesos en máquinas remotas es posible, es un asunto complejo. El usuario vuelve Una estación de trabajo es una máquina personal. El hecho de que un único usuario sea atendido por la máquina garantiza a  las aplicaciones exigentes en recursos el  tiempo de respuesta requerido. La carga que  introduce  en una máquina  la  ejecución de procesos de otras máquinas no permite que  sigamos hablando de ella como una estación personal. En consecuencia, cuando un usuario vuelve, los procesos 

registrolista de estaciones ociosas

1. La máquina se registra si esta ociosa2. Petición de

máquina ociosa + réplica

7. Ejecución del proceso

8. El proceso termina

4. Baja en registro

5. Envío del entorno

demonioremote

3. Solicitud del procesador

6. Arranca el proceso

9. Notifica al solicitante

Page 14: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

14 

 

remotos arrancados en su máquina deben de ser abortados, mejor de una forma suave. Una terminación traumática puede provocar perder el trabajo hecho. Para conseguir una terminación suave, el programa debe ser escrito para soportar esta eventualidad. Una alternativa a la terminación es migrar la ejecución a otra máquina, bien a la local (home workstation) o a otra remota. No hay problemas en mover el espacio de direccionamiento, sino recoger en el núcleo las estructuras de datos que definen el estado del proceso, como su descriptor de proceso, descriptores de ficheros abiertos, temporizadores activados, etc. Aunque no hay problemas teóricos en ello, existen muchas dificultades prácticas. En cualquiera de los dos casos, es preciso dejar la máquina en el mismo estado en el que la dejó su usua‐rio. Esto requiere no sólo matar el proceso remoto sino sus descendientes y todos sus recursos como bu‐zones, semáforos, ficheros temporales tanto en disco como en la caché, etc. También es preciso conside‐rar las llamadas RPC del proceso cuyas réplicas no han vuelto en el momento de eliminar el proceso. 

4.2.3 El modelo de fondo de procesadores Sacar provecho de las estaciones ociosas añade potencia al sistema, pero no resuelve un problema fun‐damental que es el de disponer de más UCP's que usuarios. Con el descenso del precio en los procesado‐res, puede darse el caso de un sistema en el que el número de procesadores sea 10 o incluso 100 veces mayor que el de usuarios. La pregunta que surge es cómo utilizar estos nuevos recursos. 

Una solución es construir estaciones de trabajo multiprocesador, pero resulta ineficiente, ya que dema‐siados recursos están asignados de antemano a un usuario que la mayoría del tiempo no utiliza más que una UCP. La alternativa es construir un fondo de procesadores que pueden ser asignados a los usarios so‐bre demanda. A mediada que un usuario necesita más potencia de cálculo se le asignan nuevos procesa‐dores y viceversa. La figura 4.12 ilustra la idea. La motivación del fondo procesadores está copiada de la del servidor de ficheros. Al igual que los ficheros se centralizan en un número reducido de máquinas de‐nominadas servidores de ficheros para economizar en número de discos, ventiladores, etc, se puede dis‐poner de nodos que actúan como servidores de potencia de cómputo. Los servidores de cómputo permi‐ten un ahorro de estaciones considerable en un sistema distribuido. Todas  las UCP's se disponen en un panel frontal  ‐rack‐ requiriendo un único punto de alimentación y de refrigeración. El rack puede  ir en una habitación apropiada,  fuera del acceso de los usuarios, que únicamente disponen de terminales X o terminales convencionales. Lo que es más  importante, el modelo desacopla el número de usuarios del número de UCP's, que es una característica del modelo de estaciones de trabajo. A los usuarios, el siste‐ma operativo les asigna las UCP que necesiten en cada momento de forma dinámica. 

 

 

Fig. 4.12  Un sistema basado en el modelo de fondo de procesadores. 

Page 15: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

15 

 

El modelo de fondo de procesadores se fundamenta en la teoría de colas. Los elementos básicos de esta teoría se basan en un servidor al que llegan aleatoriamente peticiones de trabajo. Cuando el servidor está ocupado, las peticiones esperan en una cola, como ocurre en tantas situaciones de la vida real, sea en supermercados, oficinas de correos o la matriculación de estudiantes, según ilustra la figura 4.13. El interés de la teoría de colas radica en que es posible obtener de ellas información de forma analítica. Sea 

λ  la tasa de entrada de peticiones por segundo del total de los usuarios y sea µ  las peticiones que el 

sistema atiende en un segundo. Si µ λ> , el sistema es estable, por que el sistema es capaz de atender 

el flujo de peticiones. Ambos valores no son constantes, sino las medias de variables aleatorias. Existirán periodos en que las peticiones superen la capacidad del servicio, formándose una cola de peticiones en espera de servicio. Estos periodos vendrán sucedidos por otros de menor número de peticiones y, por tanto, de disminución de la cola hasta su desaparición. Lo importante es que los valores medios cumplan la desigualdad anterior para garantizar la estabilidad del sistema. Se puede demostrar que el tiempo me‐dio que transcurre desde que se emite una petición hasta que se obtiene una respuesta completa viene dado por la fórmula 

T =1-µ λ

 

 

Fig. 4.13  Un sistema de colas básico. 

Supongamos ahora un sistema de n estaciones multiprocesador, cada una de ellas con un número de‐

terminado de UCP's. En cada estación, con una tasa de  llegada  λ  y una tasa de servicio  µ , el tiempo 

medio de respuesta es T. Vamos a pasar ahora del modelo de estaciones de trabajo al modelo de fondo de procesadores. Reuniendo los n multiprocesadores en un fondo de procesadores logramos una máqui‐na n veces más potente que cada una de  las estaciones  individuales, con una capacidad de servicio de nµ  peticiones por segundo. Como todas las peticiones de las n estaciones van a parar ahora al fondo de 

procesadores, esta máquina  recibe una  tasa de  solicitudes de  nλ  peticiones por  segundo. El  tiempo medio de respuesta de este nuevo sistema combinado es 

1T =1

n -n= T / n

µ λ 

que viene a decir que agrupando n pequeños recursos en un recurso n veces más potente, podemos re‐ducir el tiempo de respuesta n veces. Este resultado es teórico y, por lo tanto, puede aplicarse a todo tipo de sistemas. Es más rentable a una empresa de transportes disponer de un autobús que sale cada hora de una estación central que de cuatro minibuses que salen cada hora de cuatro puntos distintos de  la ciudad, por ejemplo. La razón es que en el primer modelo, se suceden los intervalos de tiempo en que parte de los multiprocesadores están ociosos mientras la otra parte de los multiprocesadores puede estar 

Page 16: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

16 

 

sobrecargada. En estos periodos, la potencia de cálculo de los procesadores ociosos no está aprovechado, al mismo tiempo que las peticiones en los multiprocesadores sobrecargados se sirven más lentamente. 

Desde luego, el argumento anterior es uno de los más fuertes que juega en contra del concepto de siste‐ma distribuido. A una organización se le presentan dos opciones a la hora de realizar su informatización. Supongamos que se calcula que sus procesos exigen un sistema de una potencia de 1000 millones de ins‐trucciones por segundo (MIPS). Se puede optar por un sistema centralizado de 1000 MIPS o de una red de 100 estaciones de 10 MIPS. El sistema de 1000 MIPS será 100 veces más rápido, algo que aboga por concentrar la potencia de cómputo lo más posible, justo lo contrario de lo que dicta la tendencia actual hacia sistemas distribuidos. ¿Por qué entonces esta tendencia? 

La respuesta es que el tiempo medio de respuesta de un sistema no lo es todo. Uno de los factores a fa‐vor de  los sistemas distribuidos es el costo. Si el costo de 100 PC's es muchísimo menor que el de un mainframe de 1000 MIPS, la razón prestaciones/precio juega a favor del sistema distribuido. La tolerancia a fallos es mejor en la red de PC's, así como el hecho de que no es posible construir un sistema de una potencia arbitraria debido a los límites de la tecnología actual. Es importante también no sólo el tiempo de respuesta sino  la varianza en el mismo. Los usuarios no notan tiempos de respuesta muy diferentes siempre que la interacción humana con el sistema sea lo suficientemente rápida en el caso más lento y lo que no toleran es un sistema muy rápido por término medio pero que en ocasiones se vuelve exaspera‐damente lento. Un tiempo de respuesta uniforme y suficientemente ágil es lo que garantiza el modelo de estaciones de trabajo. 

Anteriormente hemos dicho que el modelo de fondo de procesadores se fundamenta en la teoría de co‐las. Considerando que un fondo de n procesadores es n veces más potente que una estación de trabajo, la teoría de colas revela que el tiempo de respuesta del fondo de n procesadores es n veces más rápido que el tiempo de respuesta de cada una de las estaciones en particualar. Este argumento, que juega a fa‐vor de la solución del fondo de procesadores frente a la solución de las estaciones de trabajo es, desgra‐ciadamente, falaz. No es cierto que un fondo de n procesadores sea n veces más potente que un único procesador. Para sacar partido a n procesadores, es preciso descomponer un problema en n procesos que corran en paralelo, cada uno de ellos asignado a un procesador. Cuando en el sistema existen menos pro‐cesos que procesadores, los pocesadores ociosos restan potencia al sistema. Aún así, aunque el tiempo de respuesta no sea n veces mejor, el modelo de fondo de procesadores es una mejor solución distribui‐da que el espiar a otros usuarios para lanzar mandatos remotos en sus máquinas y evita los problemas que surgen a la vuelta de este. 

Por otra parte, optar por una u otra solución depende de la naturaleza del trabajo que se realiza en el sis‐tema. En un entorno de ofimática, en la que la atividad principal puede ser editar documentos y enviar correo electrónico, el modelo de estación de trabajo sea seguramente suficiente. En grandes projectos de programación, que donde  continuamente  se  invoca  el mandato make o  en  aplicaciones matemáticas donde el problema sea resolver continuamente sistemas de ecuaciones, el modelo de fondo de procesa‐dores posiblemente sea el más adecuado. 

También es posible un modelo híbrido donde cada usuario dispone de su estación de trabajo y existe un fondo de proceadores a disposición de las aplicaciones más exigentes en términos de uso de UCP. Este modelo proporciona a la vez un tiempo de respuesta adecuado y un uso eficiente de recursos. 

4.3 Asignación de procesadores Optemos por el modelo de estaciones de trabajo, el fondo de procesadores o una mezcla de ambos, es preciso un algoritmo que decida qué proceso va a ejecutar en qué máquina. Para el modelo de estacio‐

Page 17: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

17 

 

nes de trabajo, la cuestión es cuándo ejecutar un proceso remotamente y en tal caso, en qué estación. Para el modelo de fondo de procesadores, la cuestión se plantea siempre para todo proceso. De ello se ocupa esta sección. 

4.3.1 Modelos de Asignación Antes de entrar a examinar algoritmos específicos, conviene examinar algunos de los principios y las me‐tas de la asignación de procesadores. 

Sistemas homogéneos y sistemas heterogéneos Cuando  todas  las máquinas  de  un  sistema  tienen  la misma  arquitectura  se  dice  que  el  sistema  es homogéneo. En caso contrario, se dice que es heterogéneo. En sistemas heterogéneos, el ejecutable de una aplicación debe estar disponible para todas  las arquitecturas participantes. Los trabajos publicados en el ámbito de la asignación de procesadores asumen en su mayoría sistemas homogéneos, difiriendo las distintas máquinas en velocidad de ejecución. Esta asunción simplifica el problema, pero deja sin re‐solver otro que es la elección de la arquitectura. Estrategias migratorias y no migratorias Las estrategias de asignación son de dos clases. En  la primera, denominada migratoria, un proceso que ejecuta en una máquina A puede ser interrumpido para continuar ejecutando en un máquina B. En la se‐gunda, denominada no migratoria, los procesos comienzan y terminan la ejecución en la misma máquina. Los algoritmos migratorios consiguen un mejor equilibrado de carga, pero son más complejos y condicio‐nan notablemente el diseño del sistema. Parámetros objeto de optimización Un algoritmo asigna un proceso a un procesador o a otro en función de algún criterio, de algún paráme‐tro que trata de optimizarse. Este parámetro no es el mismo en todos  los sistemas. Uno de ellos es el tiempo de UCP. De lo que se trata es de, en la unidad de tiempo, maximizar el número de ciclos ejecuta‐dos en todas las UCP's conjuntamente. Otro objetivo es minimizar el tiempo de respuesta. Consideremos el ejemplo de la figura 4.14. Disponemos de dos procesadores X e Y. El procesador X puede ejecutar 10 MIPS y el Y 100 MIPS. En un momento dado, el procesador X se encuentra libre, con su cola de procesos dispuestos vacía. En  la cola del procesador Y se encuentran dos procesos que se estima tardarán cinco segundos en completar su ejecución. Dado este escenario, entran en el sistema dos procesos A y B. El proceso A tiene 100 millones de  instrucciones y el B 300. Supongamos que asignamos el proceso A al procesador X y el proceso B al procesador Y. El tiempo de respuesta en el procesador X es de 100 M / 10 M/s = 10 s y el tiempo de respuesta en el procesador Y es de 5 s+(300 M / 100 M/s) = 5 s+3 s = 8 s, lo que hace un tiempo de respuesta medio de (10+8)/2 = 9 s. La asignación, por otra parte, puede ser la opues‐ta, de modo que el procesdo A ejecute en el procesador Y, donde su tiempo de respuesta es de 5 s + (100 M / 100 M/s) = 5 s + 1 s = 6 s, y el proceso B ejecute en el procesador X, con un tiempo de respuesta de 300 M / 10 M/s = 30 s, resultando un tiempo de respuesta medio de (6+30)/2 = 18 s. Desde luego esta última asignación de los procesos a los procesadores es notablemente peor que la primera si de lo que se trata es de minimizar el tiempo de respuesta de la asignación.  

 

Fig. 4.14  Asignación de dos procesos a dos procesadores 

procesos entrantes: A: 100 M instr B: 300 M instr

procesador X10 MIPS

cola vacía cola de 5 s

procesador Y100 MIPS

Page 18: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

18 

 

4.3.2 Cuestiones de diseño de algoritmos de asignación de procesadores A lo largo de los años se han propuesto numerosos algoritmos de asignación. Las principales cuestiones que deben abordarse al elaborar un algoritmo de asignación son las siguientes: 

1. Algoritmo heurístico frente a determinístico. 2. Algoritmo distribuido frente a centralizado. 3. Algoritmo óptimo frente a subóptimo. 4. Algoritmo local frente a global. 5. Algoritmo iniciado por el servidor frente al iniciado por el cliente. 

Otras cuestionen pueden tambier examinarse, pero las anteriores son las más tratadas en la literatura. 

Algoritmo heurístico frente a determinista Los algoritmos deterministas son aquellos que asumen un completo conocimiento acerca del comportamiento y  los recursos consumidos por  los procesos. Debemos conocer  la  lista de todos  los procesos, sus tiempos de computación hasta que  terminan,  los  ficheros que utilizan, etc. Con este conocimiento  se puede hacer una asignación perfecta. Como este conocimiento exaustivo pocas veces está disponible, es preciso tomar aproxi‐maciones basadas  en  la  experiencia.  Por  ejemplo,  en una  línea  aérea  se  conoce  con bastante precisión  el número de personas que harán un determinado vuelo un determinado día del año basados en los que hubo los años atrás. En el otro extremo se encuentran los sistemas en los cuales su carga de trabajo es completamente impredeci‐ble. En ellos es preciso utilizar técnicas heurísticas. Algoritmo centralizado frente a distribuido Recoger toda la información en un único punto es útil por que permite disponer de toda la información y hacer un mejor juicio. El problema de los algorimos centralizados estriba en que son menos robustos por constituir un único punto de fallo y cargar en exceso el procesador que  los evalúa. Son más apropiados  los algoritmos distribuidos. Algoritmo óptimo frente a subóptimo Obtener  la mejor  solución  supone  regoger mucha  información  y  realizar un análisis minucios  y  costoso en términos de tiempo de cómputo, por lo que a veces una solución no ideal pero suficientemente satisfactoria y más  fácil de hallar es más conveniente. Generalmente,  los sistemas distribuidos se decantan por soluciones heurísticas, distribuidas y subóptimas. Algoritmo local frente a global Entramos en  lo que se denomina la política de transferencia. Cuando un proceso se crea en una máquina es preciso tomar  la decisión acerca de si el proceso puede ser ejecutado  localmente o en otro procesador si el local está demasiado ocupado. La cuestión fundamental aquí es si basar la decisión en infomación puramente local o esperar a disponer de datos relativos a la carga de todo el sistema. Los algoritmos locales son sencillos pero están lejos de ser óptimos. Los algoritmos globales dan resultados ligeramente mejores a un costo mucho más alto. Algoritmo iniciado por el emisor frente a iniciado por el receptor Para finalizar hablaremos de la política de ubicación. Una vez que se ha decidido que el proceso se envía a otra máquina, la cuestión es determinar esa máquina, algo que necesita de información global. ¿Cómo se difunde la  información  respecto  a  la  carga  de  las máquinas?  Según  un método  la máquina  que  crea  el  proceso  o maquina  emisora  arranca  el  intercambio  de  comunicación,  difundiendo  al  resto  de  las máquinas  que  se encuentra ocupada, a fin de que alguna de ellas la eche una mano. Según el otro método, son  las máquinas ociosas o poco cargadas las que toman la iniciativa, difundiendo su estado al resto, brindándose como recepto‐ras de procesos por ejecutar. 

4.3.3 Ejemplos de algoritmos Para comprender mejor cómo se realiza realmente la asignación de un proceso a un procesador determi‐nado, conviene discutir algunos algoritmos concretos. 

Un algoritmo determinista basado en teoría de grafos 

Page 19: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

19 

 

Este algoritmo supone un sistema con un conjunto de procesos con requisitos de memoria y UCP conoci‐dos y una matriz de  tráfico entre procesos  también conocida. Si el número de UCP's es menor que el número de procesos, varios procesos tendrán que ser asignados a una UCP. La idea es proponer una asig‐nación que minimice el tráfico en la red. El sistema puede ser representado mediante un grafo ponderado donde cada nodo es un proceso y cada arco el tráfico entre dos procesos. Si el número de UCP's es k, el problema se reduce a encontrar un par‐ticionamiento apropiado del grafo en k subgrafos sujeto a algunas restricciones como que los requisitos de memoria de los procesos de cada partición sean inferiores o iguales a la memoria disponible, etc.). Di‐rijamos nuestra atención a la figura 4.15, en la que apreciamos dos particionamientos diferentes. En ellas, los arcos que están dentro de un subgrafo representan comunicaciones internas de cada procesador, de forma que el costo no se considera por no tener que emplear los mecanismos de comunicación de la red. En la figura 4.15a el tráfico en la red es de 5+2+4+4+2+8+5+2 = 32 unidades. En la figura 4.13b el costo es de 5+2+4+4+3+5+5+2 = 30 unidades, por lo que constituye una asignación mejor dado el parámetro a op‐timizar. 

 

 

Fig. 4.15  Dos formas de asignar nueve procesos a tres procesadores. 

Un algoritmo centralizado Los algoritmos de  teoría de grafos  son de una aplicabilidad  limitada ya que  requieren de  información completa por adelantado. A continuación vamos a presentar el algoritmo arriba‐abajo. Es un algorimo heurístico que no precisa de dicha información. Es un algoritmo centralizado ya que un coordinador man‐tiene una tabla de uso con una entrada por cada estación de trabajo (por usuario) inicializada a cero. Un marcador positivo indica que el usuario está consumiendo recursos del sistema y un marcador negativo indica que el usuario necesita recursos. Un marcador a cero significa que el usuario es neutral. El propósito del algoritmo no es maximizar el uso de UCP del conjunto de estaciones de trabajo con inde‐pendencia de quién  sea el propietario de  los procesos,  sino conseguir que a  todos  los usuarios  se  les asignen los recursos de una manera justa, evitando que un usuario acapare toda la potencia de cálculo. Así, en el caso de que dos estaciones compitan por una UCP que ha quedado ociosa, el coordinador ex‐amina la tabla de uso y concede la asignación a la estación con un marcador más bajo. El marcador, por lo tanto se utiliza como una heurística o ayuda. A continuación examinamos el mecanismo de puntuación. Cuando un usuario está ejecutando proce‐sos en otras estaciones, acumula puntos de penalización a  lo  largo del tiempo como  indica  la  figura 4.16. Los puntos se acumulan más rápidamente si hay más procesos en otras máquinas. Por el contra‐rio, si una máquina solicita la ejecución remota de un proceso y no se le asigna un procesador, durante todo ese tiempo va acumulando puntuación negativa. Cuando un usuario no solicita peticiones ni tie‐ne peticiones en curso, el marcador se aproxima a cero. 

Page 20: [03] Sistemas Distribuidos - Procesadores y Procesos

UNIVERSIDAD NACIONAL DE TRUJILLOESCUELA DE INFORMATICA

20 

 

 

Fig. 4.16  Operación del algoritmo de sube‐y‐baja. 

4.4 Bibliografía 

[Tan95]  Tanenbaum, A. S., Distributed Operating Systems,   Prentice‐Hall, 1995. 

 

[Cou94]  Coulouris, G. et al., Distributed Systems, Concepts and Design,   Second Edition, Addison‐Wesley, 1994.