Practicas Programas PDF

Title Practicas Programas
Course Sistemas Operativos
Institution Instituto Politécnico Nacional
Pages 27
File Size 1.7 MB
File Type PDF
Total Downloads 635
Total Views 918

Summary

Escuela Superior de Cómputo Instituto Politécnico Nacional Sistemas Operativos Programas Ejemplo Gabriela Moedano Duran Eduardo David Ramirez Osorio Leonel Vazquez Perez Daniel Barrios Alvarado 2CM8 2 PASO DE ARGUMENTOS Programa 2-1 Ejemplo practico ejecución del programa 3 PID, UID Y VARIABLES DE A...


Description

Escuela Superior de Cómputo Instituto Politécnico Nacional

Sistemas Operativos Programas Ejemplo

Gabriela Moedano Duran Eduardo David Ramirez Osorio Leonel Vazquez Perez Daniel Barrios Alvarado 2CM8

2 PASO DE ARGUMENTOS Programa 2-1 Ejemplo practico

ejecución del programa

3 PID, UID Y VARIABLES DE AMBIENTE Ejemplo práctico

Ejecución del programa

Pregunta 3-1 Investigue con ayuda de man cual es la utilidad de la funcion getuid.

Devuelve el identificador de la llamada al proceso del usuario real Ejercicio 3-1 Modifique el codigo para imprimir también el ususario efectivo. Bajo que condiciones la impresion del usuario real y el efectio seran distintos?

Programa 3-2

4 CREACIÓN DE PROCESOS Programa 4-1 ● Ejemplo práctico



Ejecución del programa

➔ Pregunta 4-1. Vea el manual de fork y escriba qué significan los valores que devuelve. Si fork devolviese el mismo valor al proceso padre que al proceso hijo. ¿Qué problemas le ocasionaría al programador? ◆ R. En caso de éxito, el PID del proceso hijo se devuelve en el padre y 0 se devuelve en el hijo. En caso de error, -1 se devuelve en el elemento principal, no se crea ningún proceso secundario y se establece errno de manera apropiada. Si se devolviese el mismo valor al padre y al hijo el programador no podría distinguir qué proceso es quién y dificultaría la codificación de instrucciones de cada uno.

➔ Pregunta 4-2. Al ejecutar el código se imprimen tres identificadores de procesos. ¿A qué procesos corresponden dichos identificadores? ◆ R. PID corresponde al identificador de ese proceso. PPID se refiere al identificador del proceso padre. ➔ Pregunta 4-3. Imprima los valores de la variable pid antes de llamar a fork(), dentro del código hijo y dentro del código del padre (En LINUX es importante terminar siempre la cadena de impresión con el carácter especial salto de línea ‘\n’. De lo contrario podría no aparecer en pantalla al encontrarse en el buffer de salida). ¿Por qué no coincide el valor de dicha variable con el PID del proceso que imprime su valor? ◆ R. ➔ Ejercicio 4-1. Modifique el programa 4-1 para que se utilicen funciones de decisión if-else en lugar de switch.

➔ Ejercicio 4-2. Para probar lo anterior, modifique el programa 4-1 de modo que el proceso hijo quede huérfano e imprima el PID de su padre adoptivo.

Programa 4-2 ● Ejemplo práctico



Ejecución del programa

➔ Pregunta 4-4. Analice cuidadosamente el código. ¿Cuántos procesos se ejecutan en total como se encuentran enlazados entre ellos? Para verificar su respuesta, imprime el árbol de procesos que devuelve el comando pstree. ◆ R. Se ejecutan 11 procesos en total, y el que nace es padre del siguiente, así sucesivamente.

➔ Pregunta 4-5. ¿Si el ciclo for va desde 0 hasta 9 porque hay 11 impresiones? ◆ R. ➔ Pregunta 4-6. Analice la importancia de la función break en el presente código. ¿Cuántos procesos se crearían si eliminamos las líneas consecutivas if(pid != 0) y break;? (compruebe su respuesta y escriba una fórmula general para el número de procesos creados, según el valor máximo de j). ◆ R. ➔ Ejercicio 4-3. Modifique el programa para que se generen 10 procesos y todos sean hijos del mismo padre, cada proceso debe imprimir su PID y el PID de su padre.

5 TUBERÍAS Programa 5-1 ● Ejemplo práctico



Ejecución del programa

➔ Pregunta 5-1. ¿Qué cambios se darán en la ejecución del programa si quitamos la función sleep(1), y la colocamos una línea después de la llamada al sistema read?.¿Qué sucedería si no estuviese la función sleep(1)?. ◆ R. Si colocamos la función sleep(1) después de la función read se obtiene:

El proceso hijo recibe el primer carácter y dado que espero un tiempo cuando vulve a leer recibe toda la información que su padre le envió en ese lapso. Si eliminamos la función sleep(1) resulta:

La información la va recibiendo el proceso hijo dependiendo el tiempo que le de el sistema para que vuelva a ejecutarse. ➔ Pregunta 5-2. ¿Qué sucedería si no existiese la función memset? ¿Y si solo existiese al inicio del código (antes de pipe)? ◆ R. No sucede ningún cambio a la salida cuando se elimina la función memset del programa o cuando se coloca antes de pipe. ➔ Ejercicio 5-1. Modifique el programa 5-1 para determinar cuál es el tamaño de la tubería en su sistema.

El tamaño del buffer es de 8193 bytes en este caso. ➔ Ejercicio 5-2. En el programa 5-1 solo se envían datos del proceso padre hacia el proceso hijo. Modifique el programa para que se añada una nueva tubería que pueda enviar datos del proceso hijo al proceso padre. El proceso hijo debe enviar las letras del abecedario pero en minúsculas.

6 MEMORIA COMPARTIDA Código de ejemplo: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.

#include #include #include #include #include int main(int argc, char *argv[]) { int shmid, *variable; key_t llave;

13. 14. 15. 16. 17. 18. 19. 20.

llave = ftok(argv[0],'k');

21. 22. 23.

/* NOS ATAMOS A LA MEMORIA COMPARTIDA*/

24. 25. 26. 27. 28. 29. 30. 31.

if((shmid = shmget(llave,sizeof(int),IPC_CREAT | 0600)) == -1){ perror("Error en shmget"); exit(-1); }

if ((variable = (int *)shmat(shmid,NULL,0)) == (int *)(-1) ){ perror("Fallo shmat"); exit(-1); } while(1){ printf("\nIntroduzca m para modificar el valor de la variable, v para visualizarla y t para terminar:\n");

32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50.

switch(leer_car()){ case 't': /* LIBERA LA MEMORIA COMPARTIDA*/ shmctl(shmid,IPC_RMID,0); exit(0); case 'v': /* VISUALIZA LA VARIABLE*/ printf("variable = %d\n",*variable ); break; case 'm': printf("Nuevo valor de la variable en memoria compartida:\n"); scanf("%d",variable); break; default: printf("Se introdujo una letra incorrecta\n"); break; } }

51. 52. } 53. 54. int leer_car(){ 55. char letra; 56. char almacen[80]; 57.

58. scanf("%s",&almacen); 59. sscanf(almacen,"%c", &letra); 60. return letra; 61. }

Dado que dos o más procesos se pueden comunicar mediante un mecanismo IPC(inter process comunications), se requiere un identificador unico o llave de IPC que pueda servir de referencia común, a los procesos que quieran hacer uso de dicho IPC. La función ftok devuelve una llave basada en un nombre de un archivo y una letra. Para un mismo nombre de archivo y letra siempre se devuelve la misma llave. Imprima el valor de la llave y observe que es el mismo en cada ejecución.

Cambie la letra y compare la llave devuelta con la anterior.

Introduzca el nombre de cualquier otro archivo que exista en la misma carpeta( puede ser en carpeta distinta pero se requiere la ruta absoluta), como primer parámetro de ftok. Por último ponga el nombre de un archivo que no exista en el sistema. Escriba los valores de las llaves obtenidas en los casos siguientes: Llave devuelta por ftok(argv[0], ‘k’);

Llave devuelta por ftok(argv[0],’ ’);

Llave devuelta por ftok(‘

‘,’k’);

Llave devuelta por ftok(‘./chetito’ ,’k’);

Al usar shmget v amos a obtener un identificador, con el cual vamos a poder realizar llamadas al sistema que controlan la zona de memoria compartida. SU primer parametro es la llave devuelta por ftok, e  l segundo es el tamaño en bytes de la zona de memoria que se desea crear, En el tercer parametro IPC_CREAT i ndica que la memoria compartida se creara siempre y cuano otro proceso no la haya creado antes, 0666 proporciona permisos de lectura y escritura en lamemoria compartida(vease el manual del comando chmod ) . EL id devuelto por shmget e  s heredado por los procesos descendientes del actual.

7 SEMAFOROS Otro mecanismo importante en los sitemas multiproceso consiste en los semaforos. De manera analoga al funcionamiento de los semmaforos en los cruces viales, donde estos impiden el flujo de autos en una direccion y lo permiten en otra direccion perpendicular. Un semaforo en los sistemas operativos permite que se ejecuten instrucciones de un programa, mientras impide que el administrador de procesos le asigne el procesador a otros programas y en consecuencia que se ejecuten sus instrucciones. Cabe aclarar que estos procesos deben compartir el “mismo” semaforo, porque de otro modo no existira sincronizacion alguna. En realidad se tiene un conjunto de semaforos que funcionan de manera sincronizada (solo uno de ellos esta en “verde” en un momento dado) agrupados bajo un identificador unico el cual se utiliza como referencia. En muchas situaciones se utilizan los semaforos para permitir a un proceso ejecutar un conjunto de instrucciones dado, mientras se les impide a los demas procesos ejecutar ese mismo conjunto de instrucciones. Para que un semaforo cambie de estado, sera necesario que el proceso que el que se esta ejecutando realice dicho cambio. En lugar de cambiar de color, en computo, los semaforos cambian de valor. Dicho valor es un entero positivo o cero y se inicializa al inicio del programa. Las operaciones sobre el semaforo hacen que se decremente o que se incremente su valor una unidad. Pero cuando un semaforo tiene el calor de cero y se lleva a cabo un decremento, el no se va a desbloquear sino hasta que otro proceso realice una operacion de incremento sobre el semaforo y en consecuencia su valor sea uno. Asi el proceso que se encontraba bloqueado, podra realizar su operacion de decremento, dejando el valor final del semaforo en cero. De manera analoga a la memoria compartida, se debe tener una llave compartida para la creacion del semaforo. Ejemplo: compile y ejecute el codigo siguiente. 1. 2. 3. 4. 5. 6. 7. 8.

#include #include

int main(void){ int i=10,pid;

9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. }

/*Cracion del proceso hijo*/ if((pid = fork()) == -1){ perror("fork"); exit(-1); }else if (pid == 0) { while(i){ printf("proceso HIJO: %d\n", i--); } }else{ while(i){ printf("proceso PADRE: %d\n", i-- ); } }

Al ejecutarlo podemos observar que aparecen todas las impresiones de un proceso y despues las impresiones del otro proceso. Si queremos sincronizar las impresiones del proceso padre y el proceso hijo para que aparezcan alternadas, tendremos que hacer uso de semaforos como se muestra en el siguiente programa. 1. 2.

#include #include

3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22.

#include #include

23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33.

#define SEMAFORO_PADRE 1 #define SEMAFORO_HIJO 0 int main(int argc, char *argv[]){ int semid, pid, j=10; struct sembuf operacion; key_t llave; llave = ftok(argv[0], 'U'); if ((semid = semget(llave,2,IPC_CREAT|0600)) == 1) { perror("ERROR al ejecutar semget"); exit(-1); } semctl(semid, SEMAFORO_HIJO,SETVAL,0); semctl(semid, SEMAFORO_PADRE, SETVAL,1); /* Se crea el proceso hijo*/ if ((pid = fork()) == 1) { perror("ERROR al ejecutar fork"); exit(-1); }else if (pid == 0 )

34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. 47. 48. 49. 50. 51. 52. 53. 54. 55. 56. 57. 58.

{ /*Codigo correspondiente al proceso hijo*/ while(j){ /*Se realiza la operacion DOWN en el semaforo del proceso hijo*/ operacion.sem_flg = 0; operacion.sem_op = -1; operacion.sem_num = SEMAFORO_HIJO; semop(semid, %operacion, 1); printf("SOY EL PROCESO HIJO. IMPRESION: %d\n",j-- ); /*Se realiza la operacion UP en el semaforo del proceso padre*/ operacion.sem_op = 1; operacion.sem_num = SEMAFORO_PADRE; semop(semid, %operacion, 1); } /*Borramos el semaforo*/ semctl(semid,0,IPC_RMID,0); }else{

59. 60. 61.

/*Codigo correspondiente al proceso padre*/ while(j){ /*Se realiza la operacion DOWN en el semaforo del proceso padre*/

62. 63. 64. 65. 66. 67. 68. 69.

operacion.sem_flg = 0; operacion.sem_op = -1; operacion.sem_num = SEMAFORO_PADRE; semop(semid, %operacion, 1);

70. 71. 72. 73. 74. 75. 76. 77.

operacion.sem_op = 1; operacion.sem_num = SEMAFORO_HIJO; semop(semid, %operacion, 1);

78. 79. } 80. }

printf("SOY EL PROCESO PADRE. IMPRESION: %d\n",j-- ); /*Se realiza la operacion UP en el semaforo del proceso padre*/

} /*Borramos el semaforo*/ semctl(semid,0,IPC_RMID,0);

La estructura sembuf t iene la forma: struct sembuf{ ushort sem_num; short sem_op; short sem_flg; };

 s el numero del semaforo cuyo valor se encuentra comprendido entre 0 y Donde sem_num e N-1. N es el numero de semaforos agrupados bajo el mismo identificador. El valor numerico de sem_op i ndica la operacion que se va a realizar sobre el semaforo, a saber -1 indica un  s una mascara de decremento (DOWN) y 1 indica un incremento (UP). Por ultimo sem_flg e bits. semget c rea un conjunto de semaforos a los que se va a poder acceder mediante el identificador devuelto por  semget. E  l segundo parametro indica el numero de semaforos agrupados bajo el ismo identificador. El tercer parametro indica que el semaforo se creara aun cuando otro proceso lo haya creado antes. semctl p  ermite acceder a la informacion de control para un semaforo. El primer parametro es el identificador del semaforo, el segundo es el numero de semaforo al que se quiere acceder, el tercer parametro permite inicializar el valor del semaforo al que se especifique en el cuarto parametro. semop r ealiza operaciones atomicas sobre los semaforos. El segundo parametro es un apuntador a un arreglo de estructuras del tipo sembuf m  encionada anteriormente. El tercer parametro es el numero total de elementos en el arreglo de estructuras. 8 MANEJO DE ARCHIVOS El sistema operativo UNIX mantiene una interfaz sencilla para el manejo de archivos, de hecho se le utiliza tambien para el acceso a una gran cantidad de dispositivos de E/S las cuales incluyen a las tarjetas de red. Esta caracteristica brinda una potente ventaja respecto a otros sistemas operativos, que exigen extensos conjuntos de funciones para llevar a cabo operaciones similares. Por otra parte se cuenta con una caracteristica adicional que se conoce como proyeccion de archivos. Esta operacion permite reservar un area de memoria, la cual va a contener una parte o el total de un archivo, que originalmente se encuentra en el disco duro. Con esta operacion se logra un acceso mas rapido al archivo y para algunos programadores esta es la forma optima para manejar archivos. En el siguiente programa se muestra el codigo de un programa que ejecuta la copia de un archivo, de manera similar a lo que realiza el comando cp, y que utilizan llamadas al sistema POSIX.

1. 2. 3. 4. 5. 6. 7. 8. 9.

#include #include #include char buffer[BUFSIZ]; /* Region de memoria para el almacenamiento temporal de datos*/ int main(int argc, char const *argv[]) { int nbytes, origen, destino;

10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. }

if(argc != 3){ printf("Forma de uso : %s archivo_origen archivo_destino\n", argv[0] ); exit(-1); } if ((origen = open(argv[1],O_RDONLY)) == 1) { perror(argv[1]); exit(-1); } if ((destino = open(argv[2], O_WRONLY | O_TRUNC| O_CREAT,0666)) == 1) { perror(argv[2]); exit(-1); } while((nbytes = read(origen,buffer,sizeof buffer)) > 0) write(destino,buffer,nbytes); close(destino); close(origen); return 0;...


Similar Free PDFs