Ingeniería del SW Junio 2009 Ejercicio 1 (25 minutos) 2.5 puntos Se desea realizar una simulación de un sistema multicuerpo de forma concurrente con hilos de la librería <pthread.h>. Dicho sistema está definido de tal forma que el siguiente programa permite simular 100 objetos, de forma secuencial: void main() { Cuerpo objetos[100]; while(1) { for(int i=0;i<100;i++) { int choque=objetos[i].Simula(); if(choque) cout<<"El cuerpo "<<i<<" ha colisionado"<<endl; } } } Para convertir el código anterior en concurrente: a) El hilo principal lanzara tantos hilos como objetos tenga que simular. Cada hilo entrara en un bucle infinito en el que simulará uno de los objetos, cuyo índice le será pasado como parámetro al hilo en el momento de ser lanzado. b) El hilo principal entrara después en un bucle infinito que mostrara por pantalla el mensaje “Simulando…” cada 1 segundo. c) Para evitar que la salida por pantalla de los hilos quede entremezclada, se realizara la sincronización de los mismos (única y exclusivamente de la salida por pantalla) mediante una tubería POSIX. Ingeniería del SW Junio 2009 Cuerpo objetos[100]; int tuberia[2]; void* simula(void* d) { int index=*((int*)d); while(1) { int choque=objetos[index].Simula(); if(choque) { char testigo; read(tuberia[0],&testigo,sizeof(testigo)); cout<<"El cuerpo "<<index<<" ha colisionado"<<endl; write(tuberia[1],&testigo,sizeof(testigo)); } } } void main() { pipe(tuberia); char testigo; write(tuberia[1],&testigo,sizeof(testigo)); for(int i=0;i<100;i++) { pthread_create(&thid,NULL,simula,&i); } while(1) { sleep(1); read(tuberia[0],&testigo,sizeof(testigo)); cout<<"Simulando"<<endl; write(tuberia[1],&testigo,sizeof(testigo)); } } Ingeniería del SW Junio 2009 Ejercicio 2 (20 minutos) 2.0 puntos Se desea hacer un servidor C/C++ para las reservas por internet de vuelos de una compañía area, mediante sockets POSIX. Dicho servidor escuchara peticiones en su tarjeta de red con IP 192.168.1.1 y en el puerto 12345. Permitirá conectarse a un único cliente simultáneamente y queda a la espera que el cliente le envíe mensajes. Mientras el cliente este conectado y envíe mensajes, seguirá atendiendo todos los mensajes de dicho cliente. Se puede utilizar si se desea la siguiente clase: class Socket { public: Socket(); virtual ~Socket(); int Connect(char ip[],int port); //Conectar un cliente //Inicializar un servidor (encapsula la creacion del socket, el bind y el //listen int InitServer(char ip[],int port); Socket Accept(); //encapsula el accept(), y es bloqueante void Close(); int Send(char cad[],int length); //devuelve -1 en caso de error int Receive(char cad[],int length);//devuelve -1 en caso de error private: int sock; }; El servidor puede recibir mensajes de petición de información, de reserva y de cancelación. Un mensaje de petición recibido por el servidor tendrá el siguiente formato (CONSULTA Origen Destino Dia Mes Año) y será respondido con (DISPONIBLE Identificador). Para realizar la reserva el cliente enviara un mensaje (RESERVA Identificador NumeroTarjeta) y el servidor responderá (RESERVADO Localizador). A continuación se muestra un ejemplo de una operación completa: Cliente->Servidor Servidor->Cliente Cliente->Servidor Servidor->Cliente CONSULTA Madrid Hawai 30 06 2009 DISPONIBLE 012345 RESERVA 012345 11111111111 RESERVADO XDFG56 No es necesaria ninguna gestión de errores, exceptuando la desconexión del cliente. Cuando se desconecta un cliente, el servidor queda a la espera de una nueva conexión. Supóngase que se dispone de las siguientes funciones que manejan las bases de datos: // La función devuelve un número entero, que es el identificador del vuelo int Consulta(char origen[], char destino[], int dia, int mes, int año); // La función admite un identificador y devuelve una cadena “localizador” void Reserva(int identificador, char localizador[]); Ingeniería del SW Junio 2009 //SOLUCION: #include "Socket.h" void main() { Socket server,client; server.InitServer("192.168.1.1",12345); while(1) { client=server.Accept(); char buffer[500]; while(1) { if(-1==client.Receive(buffer,500)) break; char com[100]; sscanf(buffer,"%s",com); if(!strcmp(com,"CONSULTA")) { char origen[100],destino[100]; int dia,mes,agno; sscanf(buffer,"%s %s %s %d %d %d",com,origen,destino,dia,mes,agno); int vuelo=Consulta(origen,destino,dia,mes,agno); char resp[200]; sprintf(resp,"DISPONIBLE %d",vuelo); client.Send(resp,strlen(resp)+1); } if(!strcmp(com,"RESERVA")) { char localizador[100]; int vuelo; sscanf(buffer,"%s %d",com,vuelo); Reserva(vuelo,localizador); char resp[200]; sprintf(resp,"RESERVADO %s",localizador); client.Send(resp,strlen(resp)+1); } } client.Close(); } Ingeniería del SW Junio 2009 Ejercicio 3 (25 minutos) 2.5 puntos A) Impleméntese un procedimiento recursivo para mostrar en pantalla un número entero positivo en formato binario. Un ejemplo de sesión en un shell (para un ejecutable denominado conversor) sería: Entrada: conversor 32 Entrada: conversor 64 Salida: 10000 Salida: 100000 Nota: La manera más simple de realizar la tarea es ir dividiendo por dos el dato. Cada digito del número binario buscado es el resto de esa división entera. (Por ejemplo 13 en binario: 13/2 = 6; 13%2=1 // 6/2=3; 6%2=0 // 3/2 =1; 3%2=1; // 1; La conversión es 0x1101. Nótese que hay que reconstruir los restos al revés). B) Impleméntese un procedimiento que recursivamente genere los N primeros términos de la sucesión de Fibonacci, cuya definición implícita es xn = xn−1 + xn−2 ( x0 = 0, x1 = 1) . A) #include <iostream.h> //#include <stdio.h> #include <stdlib.h> void binario(int i){ if(i==1) cout<<"1"; else { binario(i/2); cout<<i%2; //Tiene que ir después de la llamada recursiva } } void main(int argc, char** argv){ if(argc!=2) cout<<"Error en el numero de parámetros"; binario(atoi(argv[1])); cout<<endl; } B) #include <iostream.h> #define N 10 int Rec(int n){ if(n = = 0) return 0; if(n = = 1) return 1; return(Rec(n-1)+Rec(n-2)); } void main(){ for(int i=0; i<N; i++) cout<<"("<<i<<")"<<Rec(i)<<endl; }