7
Práctica 6: Terminación de Procesos. Ejecución de Programas. Página 1 Práctica 6. Terminación de Procesos (exit y wait) . Ejecución de Programas (exec) . 1. Objetivos. Utilizar llamadas al sistema Linux para terminar procesos y para conocer el estado en el que finalizan otros procesos. Ejecutar programas diferentes desde un programa escrito en lenguaje C. 2. Terminación de Procesos: exit y wait. Un caso típico de programación tiene lugar cuando un proceso permanece a la espera de que termine otro proceso hijo suyo antes de continuar ejecutándose. Un ejemplo de esta situación se tiene cuando se escribe una orden en la línea de comandos y se pulsa [intro]: el proceso shell crea un proceso hijo suyo que se encarga de ejecutar la orden solicitada y no muestra el cursor (señal de espera por una nueva orden) hasta que no se ha ejecutado completamente. Como es lógico, esto no ocurre así cuando la orden se ejecuta en background. Para poder sincronizar los procesos padre e hijo, se emplean las llamadas exit y wait, cuyas declaraciones son las siguientes: #include <stdlib.h> void exit (int estado); #include <sys/types.h> #include <sys/wait.h> pid_t wait(int *estado); exit termina la ejecución de un proceso y devuelve al sistema el valor estado. Si el proceso padre del que ejecuta la llamada a exit está ejecutando una llamada a wait, se le notifica la terminación de su proceso hijo y se le envían los ocho bits menos significativos de estado. Con esta información, el proceso padre puede saber en qué condiciones ha terminado el proceso hijo. wait suspende la ejecución del proceso que la invoca hasta que alguno de sus procesos hijo finaliza. La forma de invocar a wait es: pid_t pid; int estado,edad; pid=wait(&estado);

Exit and Wait

Embed Size (px)

DESCRIPTION

Practica 6 Linux

Citation preview

  • Prctica 6: Terminacin de Procesos. Ejecucin de Programas. Pgina 1

    Prctica 6. Terminacin de Procesos (exit y wait). Ejecucin de Programas (exec).

    1. Objetivos.

    Utilizar llamadas al sistema Linux para terminar procesos y para conocer el estado en

    el que finalizan otros procesos.

    Ejecutar programas diferentes desde un programa escrito en lenguaje C.

    2. Terminacin de Procesos: exit y wait.

    Un caso tpico de programacin tiene lugar cuando un proceso permanece a la espera de

    que termine otro proceso hijo suyo antes de continuar ejecutndose.

    Un ejemplo de esta situacin se tiene cuando se escribe una orden en la lnea de comandos y

    se pulsa [intro]: el proceso shell crea un proceso hijo suyo que se encarga de ejecutar la orden

    solicitada y no muestra el cursor (seal de espera por una nueva orden) hasta que no se ha

    ejecutado completamente. Como es lgico, esto no ocurre as cuando la orden se ejecuta en

    background.

    Para poder sincronizar los procesos padre e hijo, se emplean las llamadas exit y wait, cuyas

    declaraciones son las siguientes:

    #include

    void exit (int estado);

    #include

    #include

    pid_t wait(int *estado);

    exit termina la ejecucin de un proceso y devuelve al sistema el valor estado. Si el proceso

    padre del que ejecuta la llamada a exit est ejecutando una llamada a wait, se le notifica la

    terminacin de su proceso hijo y se le envan los ocho bits menos significativos de estado. Con

    esta informacin, el proceso padre puede saber en qu condiciones ha terminado el proceso

    hijo.

    wait suspende la ejecucin del proceso que la invoca hasta que alguno de sus procesos hijo

    finaliza. La forma de invocar a wait es:

    pid_t pid;

    int estado,edad;

    pid=wait(&estado);

  • Prctica 6: Terminacin de Procesos. Ejecucin de Programas. Pgina 2

    Se obtiene en pid el valor del identificador de proceso de alguno de los hijos zombies (un

    proceso zombie es el que acaba de finalizar). En la variable estado se almacena el valor que el

    proceso hijo le enva al padre mediante la llamada a exit y que da idea de la condicin de

    finalizacin del proceso hijo. Si se quiere ignorar este valor, se puede pasar como parmetro

    un puntero NULL (pid=wait(NULL)).

    En el archivo de cabecera se definen diferentes macros que permiten analizar

    el valor de estado para determinar la causa de terminacin del proceso. En particular, el

    proceso padre puede obtener el valor de los ocho bits menos significativos del parmetro que

    recibe desde la llamada a exit por parte del hijo utilizando la macro

    WEXITSTATUS(estado).

    Si durante la llamada a wait se produce algn error, la funcin devuelve 1 y en errno

    quedar el cdigo del tipo de error producido.

    Como es lgico, si el proceso que invoca a wait no tiene ningn proceso hijo vivo, se produce

    un error.

    Por ejemplo, sea el siguiente cdigo correspondiente a un proceso cuyo pid es igual a 10 y

    que tiene un hijo con pid igual a 20:

    #include

    #include

    #include

    ...

    int main (void){

    pid_t pid;

    int estado,edad,edadHijo;

    ...

    pid=wait(&estado);

    edad=WEXITSTATUS(estado);

    printf("Mi hijo %d ha fallecido a los %d aos.\n",pid,edad);

    pid=wait(&estado);

    printf("pid=%d\n",pid);

    ...

    }

  • Prctica 6: Terminacin de Procesos. Ejecucin de Programas. Pgina 3

    Si el cdigo del proceso hijo termina con las siguientes instrucciones:

    ...

    edadHijo=140;

    exit(edadHijo);

    }

    Cuando el proceso padre llega a la instruccin wait suspende su ejecucin y permanece a la

    espera de que finalice el proceso hijo. ste finaliza cuando alcanza la instruccin exit que

    tiene como parmetro la variable edadHijo, cuyo valor es 140 en el proceso hijo.

    Es ahora cuando el proceso padre se desbloquea y la instruccin wait devuelve como

    resultado el valor del pid del proceso hijo que ha terminado (en este caso, el valor 20) y lo

    almacena en la variable pid.

    En los ocho bits menos significativos de la variable estado queda almacenado el valor de los

    ocho bits menos significativos de la variable edadHijo (parmetro de la instruccin exit del

    proceso hijo). Como es posible que el resto de bits de la variable estado tengan valores no

    deseados, se utiliza la macro WEXITSTATUS para obtener el valor correcto del parmetro

    enviado por el proceso hijo.

    As, tras finalizar el proceso hijo, el proceso padre mostrara en pantalla el siguiente mensaje:

    Mi hijo 20 ha fallecido a los 140 aos.

    Posteriormente, el padre pretende esperar a que termine otro proceso hijo (wait). Puesto que

    ya no hay ningn hijo vivo, la llamada a wait produce un error y devuelve el valor 1.

    Entonces se vuelca en pantalla el mensaje:

    pid=-1

    3. Ejecucin de programas: exec.

    Existe toda una familia de funciones exec tiles para lanzar programas ejecutables desde un

    programa escrito en lenguaje C. Dentro de esta familia cada funcin tiene su sintaxis pero

    todas tienen aspectos comunes y obedecen al mismo tipo de funcionamiento: se carga un

    programa en la zona de memoria del proceso que ejecuta la llamada sobreescribiendo los

    segmentos del programa antiguo con los del nuevo. Es decir, el programa viejo es

    SUSTITUIDO por el nuevo y NUNCA se volver a l para proseguir su ejecucin, pues es

    el programa nuevo el que pasa a ejecutarse.

  • Prctica 6: Terminacin de Procesos. Ejecucin de Programas. Pgina 4

    La declaracin de la familia de funciones exec es la siguiente:

    int execl (char *ruta, char *arg0, char * arg1,..., char *argn, (char *)0);

    int execv (char *ruta, char *argv[]);

    int execle (char *ruta, char *arg0, char * arg1,..., char *argn, (char *)0, char

    *envp[]);

    int execve (char *ruta, char *argv[], char *envp[]);

    int execlp (char *fichero, char *arg0, char * arg1,..., char *argn, (char *)0);

    int execvp (char *fichero, char *argv[]);

    Donde:

    ruta es una cadena con el path (absoluto o relativo) de un archivo ejecutable.

    fichero es el nombre de un fichero ejecutable.

    arg0, arg1,..., argn son cadenas de caracteres que constituyen la lista de parmetros que se le

    pasa al nuevo programa. Por convenio, al menos arg0 est presente siempre y coincide con

    ruta o con el ltimo componente de ruta. Hay que destacar que tras argn se pasa un puntero

    NULL para indicar el final de los argumentos.

    argv es un array de cadenas de caracteres que constituye la lista de argumentos que va a

    recibir el nuevo programa. Por convenio, argv debe tener al menos un elemento, que coincide

    con ruta o con el ltimo componente de ruta. El final de argv se indica colocando un puntero

    NULL detrs del ltimo parmetro.

    envp es un array de punteros a cadenas de caracteres que constituyen el entorno en el que se

    va a ejecutar el nuevo programa. envp tambin termina con un puntero NULL.

    Un programa escrito en C recibe estos parmetros a travs de la funcin main, que se puede

    declarar de la siguiente forma:

    void main (int argc, char *argv[], char *envp[]);

    As, por ejemplo, se podra obtener un listado completo de los archivos del directorio actual

    cuyo nombre termine con la cadena .c utilizando la instuccin execl:

    execl("/bin/ls","ls","-l","*.c", (char *)0);

    La instruccin anterior ejecuta la orden ls de igual manera que si se escribiera en la lnea de

    comandos la siguiente orden:

    ls l *.c

  • Prctica 6: Terminacin de Procesos. Ejecucin de Programas. Pgina 5

    Si hubiera ms instrucciones posteriores a execl no se ejecutaran porque el programa ls

    sustituye al que lo llama.

    En el caso de que se deseara ejecutar ms instrucciones, sera necesario crear un proceso hijo

    que se encargara de llamar a la orden execl mientras el padre podra continuar realizando

    otras tareas.

  • Prctica 6: Terminacin de Procesos. Ejecucin de Programas. Pgina 6

    4. Enunciado de la prctica.

    Escribir un programa en lenguaje C que reciba un parmetro desde la lnea de rdenes y se

    encargue de:

    - Comprobar que la sintaxis empleada ha sido adecuada y, en caso contrario,

    mostrar por pantalla cul es la correcta:

    La sintaxis correcta es: dormilones nmero_hijos

    - Crear un nmero de procesos hijo dado por el parmetro de la lnea de rdenes.

    - Cada uno de los procesos hijo generar un nmero aleatorio entre 1 y 10,

    mostrar un mensaje indicando su pid y el tiempo que va a dormir. A

    continuacin dormir ese nmero de segundos. Una vez transcurrido este

    tiempo, el proceso hijo termina con una llamada a exit tal que el proceso padre

    pueda conocer el tiempo que dicho hijo ha estado durmiendo.

    - El proceso padre, por su parte, esperar (wait) a que terminen todos sus procesos

    hijo. A medida que vayan finalizando ir mostrando el valor del pid de cada hijo

    junto con el tiempo que ha dormido.

    - Cuando todos los hijos hayan terminado, el proceso padre debe dormir durante 2

    segundos y, posteriormente, ejecutar ( execl ) el siguiente programa: ps lc.

    Por qu no se visualiza ningn mensaje si se coloca despes de la orden execl la instruccin

    siguiente?

    printf("PADRE: ejecucin terminada\n");

    Generacin de nmeros aleatorios en lenguaje C. Para generar nmeros aleatorios, el lenguaje C dispone de las funciones srand y rand, que

    aparecen en el archivo de cabecera stdlib.h.

    void srand (unsigned semilla);

    Inicializa el generador de nmeros aleatorios. La secuencia generada depende del

    valor de semilla y es siempre la misma para la misma semilla.

  • Prctica 6: Terminacin de Procesos. Ejecucin de Programas. Pgina 7

    int rand (void);

    Permite obtener un nmero aleatorio.

    Para generar un entero aleatorio entre 1 y 10 se puede utilizar el siguiente cdigo dentro de

    cada proceso hijo:

    srand(getpid());

    tiempo=1+(int)(10.0*rand()/(RAND_MAX+1.0));

    Nota: Normalmente, el generador de nmeros aleatorios se inicializa con el

    valor del reloj del sistema para evitar que se repita la misma secuencia cada

    vez que se ejecuta el programa.