S0ftware T4 y T5
|
|
Título del Test:![]() S0ftware T4 y T5 Descripción: Preguntas para el repaso de los temas 4 y 5 (Procesos y ficheros) |



| Comentarios |
|---|
NO HAY REGISTROS |
|
¿Cuántos procesos se crean en el siguiente fragmento de código? for (int i = 0; i < 3; i ++) { pid = fork(); if (pid == 0) { exit(0); } }. 1, ya que al finalizar el padre por terminación en cascada se finalizaría su ejecución. 7. 3, creados cada uno por un proceso. 3, creados todos por el padre. El valor de retorno de fork: Devuelve cuántos hijos ha tenido este proceso. Devuelve a un proceso su propio pid. Es igual para el padre y para el hijo, puesto que son indistinguibles. Es la forma de distinguir el proceso padre del hijo. Solo es importante si es menor que cero, que es un error. Une los siguientes valores de retorno de fork() con su correspondiente: Entero con el PID del hijo. 0. -1. Con fork(): Los procesos padre e hijo se ejecutan de forma concurrente y se pueden ordenar de cualquier forma. Los procesos padre e hijo se ejecutan de forma concurrente y se ordenan siempre de la misma forma. int main () { prinft("A"); fork(); fork() printf("B"); } Selecciona una: Escribe A una vez y B una veces. Escribe A dos veces y B dos veces. Escribe A una vez y B dos veces. No puede llamar a printf tras llamar a fork. Escribe A una vez y B cuatro veces. res = execv(cmd, argv); if (res < 0) { err(1, "exec %s failed", cmd); printf("exec worked\n"); Selecciones una: Nunca se imprimirá exec worked. Siempre imprimirá exec worked. Está mal: no se puede llamar a exec sin haber llamado a fork. Está mal: El printf debería estar en un else. Devuelve en res el pid del hijo o -1 si es error. La siguiente función: char* readfile(int fd) { char *p; int nr; nr = 0; do { nr = read(fd, p+nr, 200); if (nr < 0) { err(1,"read"); } } while(nr > 0); return p; }. Está mal, no se puede hacer return de un puntero. Está mal, read necesitaría usar un puntero a FILE. Está mal, tiene problemas de memoria. Está bien, lee un fichero entero a memoria y devuelve el puntero a su inicio. Está mal, no se controla bien el error de read. write(1, "hola", 4); Seleccione una: Deberías tener un 5 en lugar del 4 para poder escribir una línea en la salida estándar. Escribe cuatro caracteres en la pantalla. Escribe cuatro caracteres en la salida estándar del proceso. Debería usar 0 en lugar de 1. No compila, el segundo parámetro es incorrecto. ¿Qué es la condición de carrera entre un proceso padre y su hijo?. El proceso padre siempre espera a que su hijo termine antes de continuar su ejecución. El proceso padre y el proceso hijo acceden a recursos compartidos sin la debida sincronización, lo que puede producir resultados inesperados. Los procesos padre e hijo siempre se ejecutan en secuencia, de forma que el padre siempre ejecuta primero que el hijo. El proceso hijo tiene siempre prioridad de ejecución sobre el padre, garantizando que el hijo termine antes de que el padre ejecute su código. ¿Cuál es el valor de pid para el proceso padre en el siguiente código? int main() { int pid = fork(); if (pid == 0) { printf("Soy el hijo\n"); } else { printf("Soy el padre\n"); } return 0; }. El PID del hijo. 0. PID del padre. Negativo si ocurre un error. Número aleatorio. ¿Qué se imprime cuando se ejecuta el siguiente código? int main() { int pid = fork(); if (pid == 0) { printf("Hijo\n"); } else if (pid > 0) { printf("Padre\n"); wait(NULL); } return 0; }. Padre Hijo. Hijo Padre. Padre. Hijo. Padre Hijo Padre. ¿Qué pasa si fork() devuelve un valor negativo?. El proceso padre y el hijo terminan inmediatamente. El valor de pid es 0 y ambos procesos se ejecutan normalmente. El proceso hijo termina antes de que el proceso padre ejecute su código. La llamada a fork() falla y no se crean nuevos procesos. El proceso padre obtiene el PID del hijo y el proceso hijo recibe 0. ¿Qué se imprimirá al ejecutar este programa? int main() { int pid = fork(); if (pid == 0) { printf("Hola "); fork(); } else { printf("Adiós "); } return 0; }. Imprime un Hola y un Adiós. Imprime dos Hola y un Adiós. Imprime tres Hola. Imprime un Hola y dos Adiós. Imprime tres Adiós. ¿Qué hace la función execv() en un programa de C?. Ejecuta un nuevo programa, reemplazando el proceso actual por el nuevo programa. Crea un nuevo proceso hijo y espera a que termine. Modifica el contenido de la memoria del proceso actual sin cambiar el programa. Hace que el programa se ejecute de nuevo desde el principio. ¿Qué debe incluir el segundo parámetro de la función execv()?. Un puntero a un arreglo de cadenas que contiene los argumentos para el programa. Un puntero a una cadena que contiene el nombre del programa a ejecutar. Un puntero a un archivo que contiene los argumentos del programa. Un puntero a una variable de tipo entero que indica el número de argumentos. ¿Cuál es el valor de retorno de execv() si la ejecución es exitosa?. 0. 1. -1. No retorna. Considerando que la ruta al ejecutable es correcta, ¿cuál es el resultado de ejecutar el siguiente programa? int main() { pid_t pid = fork(); if (pid == 0) { printf("Hijo\n"); char *args[ ] = {"/bin/ls", "-l", NULL}; execv(args[0], args); printf("Error del exec\n"); } else { wait(NULL); printf("Padre\n"); } return 0; }. Hijo <ls> Padre. Hijo <ls>. Padre Hijo <ls>. No se imprime nada, el programa termina inmediatamente. Hijo Error del exec Padre. Une cada función con su correcta descripción: execv(). execlp(). execp(). ¿Qué sucede cuando se usa wait() y el hijo termina normalmente con un código de salida 0?. WIFEXITED(status) devuelve 1 y WEXITSTATUS(status) devuelve 0. WIFEXITED(status) devuelve 0 y WEXITSTATUS(status) devuelve 1. WIFEXITED(status) devuelve 1 y WEXITSTATUS(status) devuelve 1. WIFEXITED(status) devuelve 1 y WEXITSTATUS(status) devuelve -1. Une los status de salida del hijo con su correspondiente: WIFEXITED(status). WEXITSTATUS(status). WIFSIGNALED(status). WIFSTOPPED(status). WIFCONTINUED(status). La función wait(&sts): Espera a que un proceso hijo termine y devuelve el PID del hijo, guardando su código de salida en la variable sts. Espera a que un proceso hijo termine y devuelve el código de salida del hijo directamente en sts. Espera a que todos los procesos hijos terminen y almacena el código de error del último proceso hijo en sts. Espera indefinidamente hasta que todos los procesos en el sistema operativo terminen su ejecución, y no guarda ningún valor. nw = write(fd, buf, Nbytes); if (nw < 0){ err(1,”write ha fallado\n”); }. No es necesario comprobar el valor de retorno de write, siempre es Nbytes. La llamada a write puede fallar y no lo detectaría el if. Podría devolver un número menor que NBytes y no sería un error. Solo estaría bien si la condición comprobase si nw es menor o igual que 0. Nunca va a entrar en el if, write siempre devuelve Nbytes. La siguiente función: char* readfile(int fd) { char *p; int nr; nr = 0; do { nr = read(fd, p+nr, 200); if ( nr < 0) err(1,”read”); } while(nr>0) return p; }. Está mal, no se puede hacer return de un puntero. Está mal, read necesitaría usar un puntero a FILE. Está mal, tiene problemas de memoria. Está bien, lee un fichero entero a memoria y devuelve el puntero a su inicio. Está mal, no se controla bien el error de read. Si uso fread(de stdlib) para leer de un fichero de 32 en 32 bytes…. Nunca se realiza una llamada al sistema, fread accede al disco directamente, por eso es más rápido. Se comprimen los datos leídos, por eso es más rápido. No funciona, fread solo sirve para leer líneas del fichero. Se usa recolección de basura para la memoria dinámica, y por eso es más rápido. Se realizan menos llamadas al sistema de lectura que si uso directamente read, por eso es más rapido. El siguiente código: while(1) { res = execv(cmd,argv); if (res < 0) { err(1,”exec %s failed”,cmd); } }. No tiene sentido, va a ejecutar muchas veces el comando. Está bien porque considera el posible error del exec. Está mal, no va a entrar nunca en el bucle. No tiene sentido, sobra el bucle y el if. Está mal, después del exec hay que llamar a fork. El siguiente código: for(i = 0; i < 3; i++){ fork(); } fprintf(stderr,”hola\n”); exit(0);. Escribe 8 lineas en la salida de error. Escribe 8 lineas en la salida de estándar. Escribe 3 lineas en la salida de error. Escribe 3 lineas en la salida de estandar. Escribe 4 lineas en la salida de error. El siguiente código: f = fopen(“/tmp/x”,”w”); fprintf(f,”hi\n”); for(;;){ }. /tmp/x tiene 3 bytes. /tmp/x tiene 4 bytes. No se puede escribir en el directorio /tmp. /tmp/x tiene 2 bytes. Es muy posible que no se escriba nada en el fichero. Cuando un proceso llama a fork: Tiene que llamar a wait siempre. Siempre va a hacer un exec. El hijo comparte variables con el padre, tiene que tener cuidado con no sobreescribir los valores. No puede retornar de la llamada, si retorna es un error. El hijo puede dar valor a sus variables de forma independiente. Qué hace cada comando?. sleep 60 &. sleep 60 Ctrl+C. sleep 60 Ctrl+Z bg. sleep 60 & Ctrl+Z fg. sleep 60 & jobs. El siguiente código, suponiendo que el resto del programa es correcto y omitiendo la comprobación de errores: int sts; if (fork() == 0){ printf("hola\n"); exit(EXIT_SUCCESS); } else { wait(&sts); printf("adios\n"); }. Escribe dos líneas y no podemos estar seguros del orden en el que se escribirán hola y adiós. Escribe dos líneas y estamos seguros de que siempre escribe antes hola que adiós. Sólo escribe adiós. Sólo escribe hola. Escribe dos líneas y estamos seguros de que siempre escribe adiós antes que hola. En un sistema de ficheros tipo Unix: Una entrada del directorio relaciona un nombre del fichero con el i-nodo correspondiente, sólo puede haber un nombre para un i-nodo. Un i-nodo contiene los metadatos de un fichero, como su nombre, permisos y las referencias a sus bloques de datos. Usa en una tabla FAT para indexar los i-nodos con una lista enlazada con tabla. Un i-nodo contiene los datos de un fichero, una entrada de directorio contiene sus metadatos: su nombre, permisos, dueño, etc. Una entrada del directorio relaciona un nombre del fichero con el i-nodo correspondiente, puede haber varios nombres para un i-nodo. int* statusSon(int pid) { int x; waitpid(pid, &x, 0); x = WEXITSTATUS(x); return &x; }. No compila: una función no puede devolver el tipo puntero a entero. Es errónea: no existe la función waitpid para esperar a un hijo concreto. Es correcta: aunque innecesaria por ser un recubrimiento de waitpid. Es errónea: la función waitpid no devuelve el estatus del hijo. Es errónea: Devuelve la dirección de una variable local. Si tenemos un planificador Round-Robin y aumentamos mucho el tiempo de cuanto: Se desperdicia mucho tiempo en cambios de contexto. Degenera en una política SJF y provoca hambruna en los procesos dominados por CPU. Degenera en la política FCFS y provoca un efecto convoy en los procesos dominados por entrada/salida. No tiene sentido. Round-Robin no usa cuantos. Se beneficia mucho a las aplicaciones interactivas. Cuando usamos un contenedor (p. ej. de Docker) en lugar de una máquina virtual de sistema para ejecutar un Red Hat Linux sobre un Ubuntu Linux…. Hay dos Kernels de Linux ejecutando: el del sistema Ubuntu y el del Red Hat. Los contenedores sólo sirven para emular otro tipo de procesador (ISA). No se necesita ejecutar ningún Kernel de Linux, todos los programas ejecutan sin sistema operativo. Sólo hay un Kernel de Linux ejecutando. Hay tres Kernels de Linux ejecutando: el Hypervisor (VMM), el del sistema Ubuntu y el del Red Hat. Cuando se mata un proceso con el comando kill: Se le comunica al proceso cerrando un pipe. No se puede matar un proceso con ese comando. Nunca se mata un proceso con señales: es peligroso. No hay un comando kill, es una llamada al sistema. Se le manda una señal y el kernel acaba con el proceso. En un sistema de dicheros estilo Unix con i-nodos. Se usa asignación de espacio contigua. Se usa asignación de espacio indexada de 4 niveles. Se usa asignación de espacio con lista enlazada con tabla. Se usa asignación de espacio con lista enlazada. Se usa asignación de espacio indexada con esquema combinado. El objetivo de la siguiente función es escribir en la salida estándar el contenido del fichero que se le pasa como argumento: void dump(char *path) { char buf[8*1024]; int nr; int fd; fd = open(path, O_RDONLY); do { nr = read(fd, buf, 8*1024); write(1,, but, nr); } while(nr != 0); close(fd); }. Está mal porque no se puede declarar un array de chars de esa forma. Está mal porque no controla los errores correctamente y puede provocar un bucle infinito. Está bien. Está mal porque debería abrir el fichero con la opción O_RDWR | O_TRUNC. Está mal porque intenta escribir en la entrada estándar. ¿Cuáles de las siguientes afirmaciones son correctas acerca del algoritmo Round-Robin (R-R)?. Aumenta la respuesta interactiva, pero reduce el rendimiento debido al aumento de los cambios de contexto. Consiste en una cola FIFO, pero un proceso solo puede ejecutar un tiempo determinado (cuanto) antes de ser expulsado. Si la ráfaga de un proceso es más larga que el cuanto, el proceso será completado en su primera ejecución. Si la ráfaga es más larga que el cuanto, el proceso será puesto al final de la cola para seguir ejecutándose más tarde. Es ideal para sistemas con procesos de larga duración, ya que garantiza que todos los procesos tengan la misma prioridad. Todas son correctas. Políticas NO expulsivas: First Come First Serve (FCFS). Shortest Job First (SJF). Shortest Remaining Time First (SRTF). Round-Robin. Políticas expulsivas: First Come First Serve (FCFS). Shortest Job First (SJF). Shortest Remaining Time First (SRTF). Round-Robin. Une las siguientes políticas con sus principales problemas: FCFS. SJF. SRTF. Round-Robin. Si el sistema está usando enlazado dinámico con lazy binding tengo un programa con una función fnt() definida…. La dirección de memoria de la función fnt se resuelve cuando gcc compila y enlaza el programa. La dirección de memoria de la función fnt se resuelve justo antes de que comience la ejecución del programa. La dirección de memoria de la función fnt no se resuelve hasta la primera vez que la se la llama. La dirección de memoria de la función fnt se resuelve cuando el programa termina la ejecución. No se pueden usar funciones en ese caso. Une cada término de la tabla de procesos con su correspondiente: PID. PPID. UID. GID. |





