Sistemas Operativos: Procesos – Comunicación Interprocesos

Anuncio
TP4: Sistemas operativos y redes
Sistemas Operativos: Procesos – Comunicación Interprocesos – Sincronización
Ejercicio 1: ps, /proc
a) Describa que información acerca de los procesos puede obtenerse utilizando el comando ps de linux.
En particular analice las opciones a, x, e, f, g. También analice las opciones destinadas a formatear la
salida.
b) Analice el sistema de archivos virtual /proc. Enumere que información acerca de los procesos puede
obtener del mismo.
c) Haga un diagrama de estados explicando los diferentes estados en los cuales puede estar un
proceso en un Sistema Operativo tipo UNIX.
d) Indique que elementos contiene el Bloque de Control de Procesos y como lo utiliza el sistema
operativo.
e) Explique cómo puede obtenerse exclusión mutua si un procesador posee una instrucción Test&Set.
Analice la equivalencia con la instrucción Exchange (Register, Memory).
La información puede obtenerla a partir de las páginas de manual ps(1) y proc(5). (Por ejemplo
www.linuxmanpages.com )
a)
Comando: ps (process status)
Uso: ps [modificadores] [condición]
Dato: modificadores es opcional.
En particular los siguientes modificadores no toman el parámetro condición:
-a: Muestra todos los procesos de la terminal actual incluyendo los de otros usuarios.
-e: Muestra todos los procesos que se están ejecutando, no solo los que lanzamos nosotros. Por tanto
también se muestran los llamados demonios (procesos que se ejecutan en segundo plano). También se
muestran los procesos llamados "líderes de grupo de proceso" estos son procesos que solo sirven para
que se ejecuten otros procesos.
-f: Información completa. UID (identificador de user), nos dice quien inicio el proceso y stime hora
del lanzamiento del proceso.
-g: Muestra todos los procesos incluyendo grupos líderes (obsoleta excepto en sunOs).
-x: Muestra los procesos en un estilo BSD.
b)
Sistema de archives virtual /proc:
/proc incluye un directorio para cada proceso en ejecución (incluidos los procesos del kernel) en
/proc/PID dentro del mismo podemos encontrar:
/proc/PID/cmdline contiene el comando que inicio originalmente el proceso.
/proc/PID/cwd
un enlace del sistema al directorio del proceso.
1
/proc/PID/environ un archivo que contiene nombres y contenidos de las variables de entorno que
afectan el proceso.
/proc/PID/exe
un enlace del sistema al archivo ejecutable original (si aún existe).
/proc/PID/fd
un directorio que contiene un enlace simbólico para cada descriptor de archivo
abierto.
/proc/PID/root
un enlace del sistema a la ruta de la raíz, así como la ve el proceso. En la mayoría
de los procesos será /.
/proc/PID/status
un archivo que contiene información básica acerca de un proceso incluyendo su
estado de jecución y uso de memoria.
/proc/PID/task
un directorio que contiene enlaces a todas las tareas que hayan sido iniciadas por
este proceso.
/proc/PID/maps
el mapa de memoria que muestra que direcciones actualmente visibles a ese
proceso están mapeadas en que regiones de la RAM o en que archivos.
c)
d)
El bloque de control de procesos (process control block PCB) es una estructura de datos que el
sistema operativo crea y gestiona. En su interior contiene la información necesaria sobre los procesos
de modo que es posible interrumpirlos y reanudarlos más tarde. Cuando la interrupción de un proceso
ocurre se guardan en el PCB los datos de contexto, es decir, el contador de programa y los registros
del procesador, a su vez se cambia el estado del proceso a bloqueado.
e)
Las soluciones mediante software para tener exclusión mutua suelen sufrir de sobrecarga de
procesamiento y un significativo riesgo de errores lógicos.
Soporte del hardware para tener exclusión mutua:
a. Deshabilitar interrupciones: Consiste en deshabilitar las interrupciones cuando un proceso esté
por ingresar a su sección crítica de modo que no pueda ser interrumpido. Cuando finaliza la
2
sección crítica las interrupciones vuelven a habilitarse. Este método sólo es válido cuando el
sistema es monoprocesador.
b. Instrucciones máquina especiales: En un multiprocesador, varios procesadores comparten el
acceso a una memoria principal común. El acceso a una posición de memoria excluye cualquier
otro acceso a esa misma posición. Las más comunes son Test and Set y Exchange.
Tenemos algunas ventajas:
-
Aplicable a cualquier número de procesadores.
-
Simple y fácil de verificar.
-
Puede dar soporte a múltiples secciones críticas.
Y otras desventajas:
-
Se emplea espera activa de modo que cuando los procesos esperan para acceder a su
sección crítica consumen recursos del procesador.
-
Es posible la inanición.
-
Es posible el interbloqueo.
Instrucción Test and Set: (comprueba y establece)
Se define la función testset que se realiza atómicamente de modo que no esté sujeta a interrupción.
La función testset comprueba el valor de su argumento “i”. Si el valor es “0” entonces se reemplaza
por “1” y se devuelve “verdadero”. Caso contrario el valor no se cambia y se devuelve “falso”.
A la variable i se la denomina “cerrojo” y se inicializa en “0”. El único proceso que ingresa a su sección
crítica es aquel que encuentra el cerrojo en 0. Y los demás que lo encuentran en 1 se ponen en espera
activa o cíclica donde ejecuta únicamente instrucciones que continuamente leen el cerrojo. Cuando el
proceso que ejecutaba su sección crítica termina vuelve el cerrojo a 0.
Instrucción Exchange: (intercambio)
Se define una función Exchange que intercambia los contenidos de un registro con los de una posición
de memoria y se inicializa una variable compartida “cerrojo” en “0”. Cada proceso posee una variable
local “llavei” que se inicializa en “1”. El proceso que logre encontrar cerrojo en 0, es decir que su llave
pasará a ser cero por intercambiarse usando Exchange con el cerrojo, ejecutará su sección crítica y
cuando termine volverá a intercambiar devolviendo el 0 a cerrojo.
Ejercicio 2: fork(), signal(), exec()
a) Explique el funcionamiento de las funciones fork(), wait(), waitpid(), getpid() y getppid().
b) Explique el funcionamiento de la familia de funciones execv(). De un ejemplo de utilización.
c) Describa que es una señal, y como es el manejo de la misma por parte de un proceso.
d) Describa como es la utilización de los comandos del sistema operativo para enviar y recibir señales
(kill y trap).
e) Explique cómo se instala un manejador de señales.
f) De una explicación del funcionamiento del programa de ejemplo segnal.c visto en la práctica
3
g) Explique el funcionamiento de las funcione alarm() y pause().
a)
Creación de procesos: Se realiza invocando la llamada al sistema fork.
Instrucción fork():
El SO realiza una clonación del proceso que lo solicite. El proceso que solicita el servicio se convierte
en el proceso padre del nuevo proceso. La clonación se realiza copiando la imagen de memoria y la PCB.
El proceso hijo es una copia del proceso padre en el instante en que éste solicita al servicio fork. Esto
significa que los datos y la pila del proceso hijo son los que tiene el padre en ese instante de ejecución.
No hay que caer en el error de pensar que el proceso hijo empieza la ejecución del código en su punto
de inicio, sino que el proceso hijo comienza a ejecutar, al igual que el padre, la sentencia que se
encuentra después de fork().
Las diferencias que existen entre el proceso hijo y el padre son:
-
El proceso hijo tiene su propio identificador (PID).
-
El proceso hijo tiene una nueva descripción de la memoria. Aunque el hijo tenga los
segmentos con el mismo contenido, no tienen porque estar en la misma zona de memoria.
-
El tiempo de ejecución del proceso hijo es igual a cero.
-
Todas las alarmas pendientes se desactiva en el proceso hijo.
-
El conjunto de señales pendientes se pone en cero.
-
El valor que retorna el sistema operativo como resultado de fork() es distinto en el hijo que
el padre (el hijo recibe un 0 y el padre el PID del hijo).
Las modificaciones que realice el proceso padre sobre sus registros e imagen de memoria después de
fork no afectan al hijo y, viceversa. Sin embargo, el proceso hijo tiene su propia copia de los
descriptores del proceso padre. Esto hace que el hijo tenga acceso a los archivos abiertos por el
proceso padre. El padre y el hijo comparten el puntero de posición de los archivos abiertos en el
padre.
Sincronización de procesos:
En caso de que se desee que el padre espere a alguno de sus hijos.
Instrucción wait():
La llamada al sistema wait() pausa el proceso que la llama hasta que una señal es recibida o uno de sus
procesos hijos termina.
Instrucción waitpid():
A diferencia de wait(), waitpid() espera a un hijo en particular, el cual es identificado porque se le
pasa como parámetro el PID del hijo que se desea esperar.
El valor de PID se obtiene como el valor que devuelve la instrucción fork() al crear ese hijo.
4
Instrucción getpid():
Se utiliza cuando en un proceso se quiere conocer el PID del propio proceso.
Instrucción getppid():
Se utiliza cuando en un proceso se quiere conocer el PID del padre de dicho proceso.
b)
La familia de funciones exec(), cuando una de ellas se ejecuta, se reemplaza la imagen de un proceso
actual por la de un comando o programa que invoquemos. Se diferencian entre ellas en función de cómo
queramos realizar la llamada.
Su primer argumento es el fichero ejecutable que queremos llamar. Las funciones terminadas en “e”
(execle() y execve()) reciben otro argumento que es un puntero a las variables de entorno.
La función execv(), recibe dos argumentos, la ruta al fichero ejecutable y un arreglo con los
parámetros que queremos pasar. Este arreglo tiene la misma estructura que argv[], es decir, tiene
como primer elemento el propio programa llamado y finaliza con un puntero NULL.
El programa invocado hereda el PID del invocador.
Ejemplo del uso:
“Cree un programa al que se la pasan como argumentos nombres de archivos, luego el programa
haciendo uso de la llamada al sistema execve() debe llamar a 'cat' para que este los muestre en la
salida estándar concatenados”
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main(int argc, char *argv[], char *envp[])
{
execve(“/usr/bin/cat”, argv, envp);
printf(“Esto no se imprimira!!!”);
return 0;
}
c)
Señales:
El sistema utiliza señales para informar a un determinado proceso sobre alguna condición. La señal en
sí no es portadora de datos. Todas las señales pueden ser ignoradas o bloqueadas, a excepción de
SIGSTOP y SIGKILL, que son imposibles de ignorar.
Las limitaciones de las señales son: 1. No tienen prioridades relativas entonces cuando llegan juntas,
pueden ser tratadas en cualquier orden. 2. Si dos señales iguales llegan juntas son tratadas como una
única señal.
5
Para enviar señales desde un proceso se utiliza la instrucción kill(). Que puede enviar cualquier tipo de
señal siempre y cuando tengamos los permisos adecuados. Kill() recibe dos parámetros, el PID del
proceso al cual se le quiere enviar la señal y la señal a enviar.
d)
Si queremos enviar señales desde la línea de comandos se utiliza el comando “kill”. Y se pasa como
parámetros el PID del proceso al cual mandar la señal y el número de señal a enviar.
e)
La llamada al sistema signal() instala un nuevo manejador de señal para el número de señal pasado como
parámetro. El manejador de señal se establece como una función específica por el usuario, una de las
siguientes macros: SIG_IGN (No tener en cuenta la señal) o SIG_DFL (Dejar la señal con su
comportamiento predefinido).
Los manejadores de señales son rutinas que se llaman en cualquier momento en el que el proceso
recibe la señal correspondiente.
f)
El programa segnal.c:
1. Se declara la función trapper() que acepta como parámetro un entero.
2. Se capturan todas las señales, es decir de la 1 a la 64 llamando a signal() para cada una.
3. El programa obtiene su PID con getpid() y espera a que llegue una señal con pause().
4. Al recibir una señal el programa llama a la función trapper().
5. Lo primero es volver a enlazar la señal a para que pueda volver a ser capturada.
6. Luego termina.
g)
Instrucción pause():
La llamada al sistema pause() bloquea el proceso hasta la recepción de una señal. Se utiliza para no
gastar ciclos de CPU mientras se espera la llegada de una señal. La llamada al sistema pause() solo
retorna luego de haberse ejecutado un manejador de señal.
Para que la señal que deseamos esperar sea capturada debe identificarse que así se desea
anteriormente con la instrucción signal() que recibe dos parámetros, el primero es el número de señal
a capturar y el segundo un puntero a una función que se encargará de tratar la señal especificada.
Instrucción alarm():
La llamada al sistema alarm() causa el envío de una señal SIGALRM al proceso que la invoca luego de
una cierta cantidad de segundos que son pasados como argumento.
Las alarmas no se colocan en la pila, esto significa que sucesivos llamados a alarm() resetean el tiempo
de envío (al final se recibe una sola alarma con el último tiempo seteado). Si se pasa 0 como argumento
se cancela automáticamente cualquier alarma.
6
Documentos relacionados
Descargar