APELLIDOS NOMBRE Nº Mat. UNIVERSIDAD POLITÉCNICA DE MADRID ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA Y DISEÑO INDSUTRIAL Departamento de Ingeniería Eléctrica, Electrónica, Automática y Física Aplicada ASIGNATURA: SISTEMAS INFORMÁTICOS INDUSTRIALES CURSO 4º GRUPO Julio 2017 2. Problema de Análisis y Diseño Orientado a Objetos (5 puntos - 30 minutos) Calificación #include <string> #include <iostream> using namespace std; class Coche protected: string modelo; Coche() modelo = "Sin definir"; virtual string getdescripcion() return modelo; virtual double getprecio() = 0; virtual ~Coche() cout << "~Coche()\n"; ; class OpcionesCoche : public Coche virtual string getdescripcion() = 0; virtual ~OpcionesCoche() cout<<"~opcionescoche()\n"; ; class SeatLeon : public Coche SeatLeon() modelo = "SeatLeon"; virtual double getprecio()return 12000; ~SeatLeon() cout<<"~seatleon()\n"; ; class Navegador: public OpcionesCoche Coche *base; Navegador(Coche *b)base = b; string getdescripcion() return base->getdescripcion() + ", Navegador"; double getprecio() return 300 + base->getprecio(); ~Navegador()cout << "~Navegador()\n"; ; class AireAcondicionado : public OpcionesCoche Coche *base; AireAcondicionado(Coche *b)base = b; string getdescripcion() return base->getdescripcion() + ", Aire Acondicionado"; double getprecio() return 450 + base->getprecio(); ~AireAcondicionado()cout << "~AireAcondicionado()\n"; ; int main() Coche *modelo = new SeatLeon(); cout << "Modelo base " << modelo->getdescripcion() << " precio " << modelo->getprecio() << " euros\n"; modelo = new Navegador(modelo); cout << modelo->getdescripcion() << " cuesta " << modelo->getprecio() << " euros\n"; modelo = new AireAcondicionado(modelo); //modelo = new TechoSolar(modelo); cout << modelo->getdescripcion() << " cuesta " << modelo->getprecio() << " euros\n"; delete modelo; Dado el siguiente código, se pide. 1. Ingeniería inversa del código adjuntado (2 puntos). 2. Salida de la consola con la ejecución del programa (2 puntos). 3. Implementación de la clase TechoSolar en C++. Suponga que esta opción tiene un precio de 750 (1 punto).
1. 2. Modelo base Seat Leon precio 12000 euros Seat Leon, Navegador cuesta 12300 euros Seat Leon, Navegador, Aire Acondicionado cuesta 12750 euros AireAcondicionado() OpcionesCoche() Coche() 3. class TechoSolar : public OpcionesCoche Coche *base; TechoSolar(Coche *b) base = b; string getdescripcion() return base->getdescripcion() + ", Techo Solar"; double getprecio() return 750 + base->getprecio(); ~TechoSolar() cout << "~TechoSolar()\n"; ;
APELLIDOS NOMBRE Nº Mat. UNIVERSIDAD POLITÉCNICA DE MADRID ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA Y DISEÑO INDSUTRIAL Departamento de Ingeniería Eléctrica, Electrónica, Automática y Física Aplicada ASIGNATURA: SISTEMAS INFORMÁTICOS INDUSTRIALES CURSO 4º GRUPO Julio 2017 Calificación 3. Problema de Análisis y Diseño Orientado a Objetos (5 puntos - 30 minutos) Se está programando un juego de realidad virtual. En dicho juego aparecen personajes virtuales que realizan tareas cotidianas. Existe un personaje controlado por el jugador, y existe otro controlado por el programa que es el cajero de una tienda, el cual gestiona una determinada caja. Se está desarrollando la funcionalidad que permite a un jugador realizar un pago a un cajero. Para probar esta funcionalidad, la función main() invoca la función Recibe() del jugador con 300 unidades de dinero, que incrementa su saldo. Cuando el main() le ordena a un personaje (en este caso, el jugador) que pague 50 unidades, decrementa su saldo en dicha cantidad, que recibe su interlocutor (en este caso, el cajero). El cajero, en lugar de quedárselo, debe ingresarlo en la caja, y luego sacar su comisión de la misma, que es la que incrementa su saldo. Considérese que el saldo inicial de los personajes es de 100 unidades de dinero y el de la caja 1000. Se pide: 1. Diagrama de Clases de Diseño (DCD) que soporte el diagrama y requisitos anteriores. (2.5 puntos) 2. Código C++ de la aplicación completa, incluyendo el main() de prueba. (2.5 puntos)
#include <iostream> using namespace std; class Caja float saldo; Caja()saldo=1000; void Ingresa(float cantidad)saldo+=cantidad; void Saca(float cantidad)saldo-=cantidad; ; class Personaje protected: float saldo; Personaje* interlocutor; Personaje()saldo=100; void Conecta(Personaje* p)interlocutor=p; virtual void Recibe(float cantidad)saldo+=cantidad; ; class Cajero : public Personaje Caja* p_caja; void Gestiona(Caja* c)p_caja=c; void Recibe(float cantidad) p_caja->ingresa(cantidad); p_caja->saca(cantidad*0.05f); saldo+=cantidad*0.05f; ; class Jugador : public Personaje void Paga(float cantidad) saldo-=cantidad;interlocutor->recibe(cantidad); ; int main() Cajero cajero; Jugador jugador; Caja caja; jugador.conecta(&cajero); cajero.gestiona(&caja); jugador.recibe(300); jugador.paga(50);
APELLIDOS NOMBRE Nº Mat. UNIVERSIDAD POLITÉCNICA DE MADRID ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA Y DISEÑO INDSUTRIAL Departamento de Ingeniería Eléctrica, Electrónica, Automática y Física Aplicada ASIGNATURA: SISTEMAS INFORMÁTICOS INDUSTRIALES CURSO 4º GRUPO Julio 2017 Calificación 4. Problema de Sistemas Operativos (7,5 puntos - 45 minutos) Conteste en el espacio reservado al efecto Se desea diseñar un sistema de recomendación de hoteles, restaurantes y bares, similar al sistema de TripAdvisor. Para ello se diseña una solución Cliente-Servidor, con servidor dedicado, que atiende a cada cliente que solicita información o introduce información sobre dichos establecimientos. Los usuarios pueden conectarse al sistema a través de una app, que se instala en el móvil, o a través de un navegador web, accediendo a una determinada página web. Sea cual sea la manera de conectarse, el cliente contactará al servidor para realizar una consulta sobre un establecimiento o insertar comentarios sobre un determinado establecimiento. Para diseñar el servidor, se utiliza una base de datos que se implementa como un conjunto de ficheros, un fichero para los hoteles, otro para los restaurantes y otro para los bares. a) [1,5 ptos] Indicar para el escenario propuesto las ventajas y desventajas de Cliente-servidor con servidor dedicado frente a una solución de Cliente-Servidor serie. La solución cliente-servidor con servidor dedicado consiste en que el servidor crea un proceso hijo o un hilo que atiende las peticiones del cliente, pudiendo el servidor principal atender a otros clientes de manera concurrente. Por tanto, esta solución proporciona todas las ventajas que ofrece la concurrencia, siendo más eficiente esta solución para atender varios clientes. Por el contrario, la solución de Cliente-Servidor serie serializa los accesos de los clientes, como su nombre indica, provocando contención en otros clientes que no serán atendidos hasta que el cliente anterior finalice. La ventaja de esta última solución es que no tiene problemas de concurrencia, dado el carácter serie de dicha solución. Pero es inadmisible si un cliente lleva a cabo un servicio muy largo. b) [1,5 ptos] Indicar el mecanismo que debería utilizar la parte cliente de la aplicación para conectarse con el servidor cuando envía un comentario sobre un determinado establecimiento. Justificar la respuesta. Dado que se trata de diferentes máquinas, necesitamos utilizar sockets. Como no queremos perder ningún mensaje por parte de los clientes, se utilizarán sockets de tipo stream, utilizando protocolo TCP. c) [1,5 ptos] Implementar en código C dicho cliente. Suponed que el comentario mandado es una cadena de caracteres. int main(int argc, char * argv[]) /* suponemos que argv[1] contiene el nombre del servidor y argv[2] el mensaje a mandar*/ int cd; struct hostent * hp; struct sockaddr_in s_ain; hp = gethostbyname(argv[1]); bzero((char *)&s_ain, sizeof(s_ain)); s_ain.sin_family = AF_INET; memcpy (&(s_ain.sin_addr), hp->h_addr, hp->h_length); s_ain.sin_port = htons(port_number); cd = socket(af_inet, SOCK_STREAM, IPPROTO_TCP); connect(cd, (struct sockaddr *)&s_ain, sizeof(s_ain)); // suponemos que BUFF_SIZE es el tamaño máximo del mensaje sendv(cd, argv[2], BUFF_SIZE, 0); close(cd);
En la parte servidora, se diseña una solución multihilo (un proceso formado por hilos, denominado gest_recomend), donde hay varios hilos que acceden al fichero de hoteles, varios hilos que acceden al fichero de restaurantes y varios hilos que acceden al fichero de bares, para consultar y/o modificar los mismos de manera concurrente. d) [1,5 ptos] Describir los posibles problemas de concurrencia que pueden existir en la aplicación, indicando qué mecanismos se podrían utilizar para resolverlos. Justificar la respuesta. Los hilos van a poder acceder concurrentemente a los diferentes ficheros. Mientras que no hay problema en leer los ficheros de manera concurrente, la modificación de una zona del fichero debe hacerse en exclusión mutua. Se trata de un problema típico lectoresescritores. Podríamos utilizar diferentes mecanismos, como mutex y condiciones (que están recomendados para hilos), pero dado que se trata de ficheros, el uso de cerrojos nos facilita el establecer las restricciones de acceso de lectura y escritura sobre diferentes zonas de los mismos. Por tanto, elegiríamos los cerrojos como mecanismo de sincronización. Aparte del proceso gest_recomend, en la parte servidora y dentro de la misma máquina, hay otro proceso pesado denominado backup, que se encarga de ir almacenando todos los cambios en un fichero denominado fich_backup. El proceso backup duerme y cada 30 minutos se despierta para ir volcando los cambios producidos. El proceso gest_recomend utiliza un FIFO para comunicarle los cambios al proceso backup, que los lee, volcándolos al fichero fich_backup. e) [1,5 ptos] Implementar en código C el proceso backup. Considerar que los cambios se representan por una cadena de caracteres que se irá agregando al final del fichero fich_backup. Por simplicidad, no se tratan los posibles errores int main(int argc, char * argv[]) int fifo, fd; char mensaje[buff_size]; while (1) /* se supone que el FIFO ha sido creado por el proceso gest_recomend */ fifo = open( fifo_backup, O_RDONLY); /* se abre el fichero fich_backup para escribir al final y crearlo si es la primera vez */ fd = open ( fich_backup,o_creat O_WRONLY O_APPEND, 0666); read(fifo, mensaje, BUFF_SIZE); write(fd, mensaje, BUFF_SIZE); close(fifo); close(fd); sleep(30*60); La llamada sleep() también podría ser sustituida por el uso de alarm() más sigaction().
APELLIDOS NOMBRE Nº Mat. UNIVERSIDAD POLITÉCNICA DE MADRID ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA Y DISEÑO INDSUTRIAL Departamento de Ingeniería Eléctrica, Electrónica, Automática y Física Aplicada ASIGNATURA: SISTEMAS INFORMÁTICOS INDUSTRIALES CURSO 4º GRUPO Julio 2017 5. Problema de Sistemas Operativos (7,5 puntos - 45 minutos) Conteste en el espacio reservado al efecto Calificación a) [2,5 ptos] Un usuario invoca desde el terminal el mandato programaa. Este proceso crea un hijo. El proceso padre envía al hijo la señal SIGUSR1 transcurridos 3 segundos desde el inicio de la ejecución del proceso padre y el proceso hijo imprime un mensaje por la salida estándar indicando que se ha producido la recepción de la señal. El proceso hijo debe ejecutar el mandato ls -alt /tmp una vez que han pasado 10 segundos desde su creación. Al concluir la ejecución del proceso hijo tras la ejecución del mandato ls, también debe mostrarse al usuario en el terminal los identificadores de ambos procesos. Especifique el código necesario para que los procesos completen la ejecución correctamente y que ambos siempre devuelvan el estado en el que terminan su ejecución. pid_t pid; void funcion1(int senal) if (senal == SIGUSR1) printf("se ha recibido la Senal SIGUSR1\n"); else if (senal == SIGALRM) printf("han transcurrido los 10 segundos\n"); execlp("ls","ls","-alt","/tmp",null); perror("no se ha podido ejecutar el exec"); exit(1); void funcion2(int senal) aux=kill(pid,sigusr1); if (aux == -1) perror("kill SIRUSR1"); int main(void) int status; struct sigaction act; act.sa_handler=&funcion2; act.sa_flags=sa_restart; sigaction(sigalrm,&act,null); alarm(3); pid=fork(); if (pid == -1) perror("error en fork"); exit(1); else if (pid == 0) act.sa_handler=&funcion1; act.sa_flags=sa_restart; sigaction(sigusr1,&act,null); sigaction(sigalrm,&act,null); alarm(10); while (1) else pid=wait(&status); if (pid>0) printf("fin del hijo: %d\n",pid); else perror("error en el wait"); printf("fin del padre: %d\n",getpid());
b) [1,5 ptos] Indique si sería posible resolver el apartado b) utilizando una solución basada en threads en lugar de procesos pesados y en caso afirmativo especifique el código. No es posible porque al invocar el servicio exec desde algún thread del proceso se sustituye su imagen de memoria por la del nuevo mandato que se pasa como argumento, en este caso el mandato ls. Por lo tanto, los mensajes con los identificadores de threads o del proceso que debían mostrarse al usuario una vez concluida la ejecución del mandato ls no podrían mostrarse en este caso. c) [1 pto] Describa las posibles situaciones que pueden darse ante la finalización de un proceso hijo con pid 4444 en función de si el padre con pid 333 termina antes que él. Suponga la siguiente jerarquía de procesos: 1-22-333-4444-55555 El proceso hijo 4444 puede quedar huérfano si el padre 333 ha invocado el servicio wait antes de su finalización. En este caso, el hijo es heredado por el proceso init 1 que espera en un bucle infinito la terminación de sus hijos. También puede quedar como zombi si termina y el proceso padre 333 no ha hecho un wait. En este caso, no puede entregar el estado de terminación al padre y no se libera su entrada en la tabla de procesos. d) [1 pto] Enumere señales que al recibirlas un proceso, su acción por defecto no provoca su muerte. SIGCHLD, SIGSTOP, SIGCONT e) [1,5 ptos] En un sistema UNIX que dispone de memoria virtual con páginas de 8 KiB, indique cómo pueden compartir una región de memoria un proceso padre con sus hijos sin que exista soporte físico de esta región en el sistema de ficheros. El tamaño solicitado para la región será de 15 KB. Especifique la invocación del servicio que permite crear esta región e indique cuál será el tamaño de la región tras su creación. Antes de la invocación del servicio fork para crear los hijos, el proceso padre crea una región en memoria con el servicio mmap activando el flag MAP_SHARED, que permite compartir la región entre varios procesos, y utilizando el flag MAP_ANONYMOUS, que no asocia la región a ningún fichero en disco: char *p; p=mmap(null,15000,prot_read PROT_WRITE,MAP_SHARED MAP_ANONYMOUS,-1,0); Como el tamaño de la región debe ser múltiplo de la página del sistema, la solicitud de 15 KB se convertirá en una región de 16 KiB.