====== Examen (Final) - 75.42. Taller de programación I ====== **Cátedra:** Veiga\\ **Fecha:** 1er Cuatrimestre 2006\\ **Día:** 25/07/2006 Esta página está incompleta; podés ayudar completando el material. ===== Enunciado ===== 1) **Escriba un pequeño programa** que, sin validar errores, **acepte una única conexión TCP en el puerto 1120, reciba** paquetes de 32 bytes y los **devuleva**. El programa debe terminar al recibir un paquete de 32 '\0's. 2) ¿Cómo se lanza un **nuevo hilo (thread)** dentro de un programa? **Ejemplifique**. 3) Escribir **un programa ANSI C** que reciba 2 números por línea de comandos (a y b) El programa debe crear el **archivo x.bin con b caracteres a**. 4) Escriba una **biblioteca ANSI C** para números enteros, con las funciones sumar, restar, dividir y multiplicar. **Detalle el .H a proveer y el .C con las definiciones pertinentes**. 5) La función **sleep** permite dormir a un **hilo (thread)** durante un tiempo T especificado. ¿Es este tiempo T cumplido de forma **exacta, mínima o máxima? Jusitifique.** 6) ¿Cual es el propósito y uso de la función **LISTEN**?. 7) Un programa **ANSI C** esta formado por A.C (que incluye A.H), B.C (que incluye A.H y B.H) y C.C (que incluye C.H, que a su vez incluye el B.H). ¿Qué módulos se **compilan** si se hace un **MAKE** después de **retocar una declaración** en B.H? ¿Y si sólo se agrega un **comentario** en A.H?. **Justifique**. 8) El lenguage **ANSI C++** prevee la posibilidad de que un **constructor** sea **privado**. ¿Tiene esto sentido? **Justifique**. 9) **Declare** una **clase** (con templates) **Arreglo** que permita organizar una colección de objetos **T** en un arreglo. ingluya constructor default, constructor de copia y operadores <<, =, [] e int. 10) **Escriba una rutina** (para ambiente gráfico Windows o Linux) que dibuje una cruz del tamaño de la ventana. ===== Resolución ===== ==== 1) ==== '' #include \\ #include \\ #define PUERTO 1120\\ #define TAM_BUF 32\\ int main (void){\\ \ WORD wVersionReq = MAKEWORD (lob, hib);\\ \ WSADATA wsaData;\\ \ return WSAStartup ( wVersionReq, & wsaData);\\ \ SOKET escucha = socket (AF_INET, SOCK_STREAM, 0);\\ \ SOCKET cliente;\\ \ SOCKADDR_IN info;\\ \ memset (&info, 0, sizeof(info));\\ \ info.sin_family = AF_INET;\\ \ info.sin_port = htons ( PUERTO );\\ \ bind (escucha, &info, sizeof(info));\\ \ listen (escucha, 1);\\ \ /* se reutiliza el struct info */\\ \ cliente = accept( escucha, &info, sizeof(info));\\ \ /* como no se necesita mas el servidor se cierra */\\ \ closesocket(escucha);\\ \ /* la condicion de salida es que toda la cadena recibida sea 0 */\\ \ char salida[TAM_BUF];\\ \ memset(&salida, 0, sizeof(salida));\\ \ char recibido[TAM_BUF];\\ \ int seguir = 1;\\ \ do{\\ \ \ int recibidos = 0;\\ \ \ while (recibidos != TAM_BUF)\\ \ \ {\\ \ \ \ int resultado = recv (cliente, (&recibido) + recibidos, sizeof(recibido) - recibidos);\\ \ \ \ recibidos += resultado;\\ \ \ }\\ \ \ /* si lo recibido es distinto a la condición de salida, se sigue*/\\ \ \ seguir = memcmp( (void*) recibido, (void*) salida, TAM_BUF);\\ \ \ if (seguir)\\ \ \ {\\ \ \ \ int enviados = 0;\\ \ \ \ while (enviados != TAM_BUF)\\ \ \ \ {\\ \ \ \ \ int resultado = send (cliente, (&recibido) + enviados, sizeof(recibido) - enviados);\\ \ \ \ \ enviados += resultado;\\ \ \ \ }\\ \ \ }\\ \ }while (seguir);\\ \ closesocket(cliente);\\ \ WSACleanup ();\\ \ return 0;\\ }\\ '' ==== 2) ==== Una de las formas de lanzar un hilo usando la API de Windows es con la función **CreateThread** que devuelve un **handle** al hilo y recibe (entre otras cosas) la función que implementa la funcionalidad del hilo, un parametro que se le pasará a esa función y una variable donde almacenar el id del hilo. '' void funcionHilo (void* param)\\ { \ int* termino = (int*) param;\\ \ *termino = 1;\\ }\\ int main (void)\\ {\\ \ int id, *parametro;\\ \ *parametro = 0;\\ \ HWND handleh = CreateThread(NULL,0,funcionHilo,parametro,0,&id);\\ \ while(!(*parametro)) /* se espera a que termine el hilo*/\\ \ \ Sleep(0);\\ \ closehandle(handleh);\\ \ return 0;\\ }\\ '' ==== 3) ==== '' int main( int argc, char* argv[] )\\ { \ /* supongo que a es el primer parametro pasado al programa */\\ \ char a = atoi (argv[1]);\\ \ int b = atoi (argv[2]);\\ \ FILE* arch = fopen ("x.bin", "wb");\\ \ int escritos = 0;\\ \ for (; escritos < b; escritos++) putc (a, arch);\\ \ fclose (arch);\\ \ return 0;\\ } '' ==== 4) ==== '' /* matematica.h */\\ #ifndef __MATEMATICA__H__\\ #define __MATEMATICA__H__\\ static int error;\\ /* función para inicializar la biblioteca */\\ void inicializar();\\ /* función para destruir la biblioteca */\\ void destruir();\\ /* PRE: biblioteca inicializada \\ POS: devuelve op1 + op2 */\\ int sumar (int op1, int op2 );\\ /* PRE: biblioteca inicializada \\ POS: devuelve op1 - op2 */\\ int restar (int op1, int op2 );\\ /* PRE: biblioteca inicializada \\ POS: devuelve op1 * op2 */\\ int multiplicar (int op1, int op2 );\\ /* PRE: biblioteca inicializada \\ POS: devuelve op1 / op2 si op2 != 0 \\ si op2 == 0 se activa el flag de error y el resultado es indeterminado */\\ int dividir (int op1, int op2 );\\ /* PRE: biblioteca inicializada \\ POS: devuelve un valor distinto de 0 si el flag de error esta activado */\\ int isError();\\ #endif\\ /* matematica.c */\\ void inicializar()\\ {\\ \ error = 0;\\ }\\ void destruir(){}\\ int sumar (int op1, int op2 )\\ {\\ \ return op1 + op2;\\ }\\ int restar (int op1, int op2 )\\ {\\ \ return op1 - op2;\\ }\\ int multiplicar (int op1, int op2 )\\ {\\ \ return op1 * op2;\\ }\\ int dividir (int op1, int op2 )\\ {\\ \ if (op2 == 0)\\ \ \ error = 1;\\ \ else\\ \ \ return op1 / op2;\\ \ return 0;\\ }\\ int isError()\\ {\\ \ return error;\\ }\\ '' Una alternativa por la que optaron otros estudiantes que rindieron el examen es declarar al flag (//error//) como **extern** lo que permite que sea accedido desde fuera del modulo, evitando tener que definir funciones (como //isError//) para conocer su valor. Sin embargo la alternativa mostrada se orienta al encapsulamiento al estilo de **TDA** (//**T**ipo de **D**ato **A**bstracto//). ==== 5) ==== Según las especificaciones el tiempo T indicado será el mínimo tiempo que el hilo estará "dormido", este tiempo dependerá del sistema operativo y de lo ocupado que este el procesador. Esto es debido a que en un S.O. multi tarea el tiempo de procesamiento es compartido entre todos los hilos ejecutandose por un intervalo de tiempo alternativamente cada uno; si alguno de los hilos requiere mucho uso del procesador (ya que esta realizando alguna tarea que lo necesita) el S.O. le dará mayor tiempo de uso a dicho hilo, esto hará que los demás deban esperar para ser atendidos. Dado que un hilo que esta "durmiendo" no requiere uso del procesados, si cuando debería volver a actividad el hilo por haber trancurrido el tiempo especificado en la funcón **Sleep**, hay otro hilo que requiere un uso intensivo del procesador, el hilo que estaba "durmiendo" deberá seguir esperando; por esta razon puede suceder que el tiempo en que el hilo esta inactivo sea mayor que el especificado. ==== 7) ==== Tanto si se retoca una declaración o modifica un comentario en algun archivo, la fecha de modificación del mismo cambiará con respecto a la que tenia previamente, por esta razón al hacer un **MAKE** se recompilarán todos los archivos que utilizen los modificados. Por esta razón al modificar **B.H** se deberán recompilar los archivos **B.C** y **C.C** que son los que lo incluyen; si se modifica **A.H** se recompilarán **todos** los archivos **.C** ya que directa o indirectamente lo incluyen. ==== 8) ==== Declarar un constructor privado tiene sentido cuando se desea que no se puedan crear instancias de la clase desde afuera de la misma, al declararse un constructor con visivilidad **private** se logra que **no** se genere el constructor **por defecto** que existe cuando no se declara constructor alguno. La declaración de un constructor **privado** se usa por ejemplo en la implementación del **patrón de diseño Singleton** en el cual se desea que exista una **única** instancia de la clase y por lo tanto no se desea que se puedan instanciar objetos desde afuera de la misma. ==== 9) ==== '' #ifndef __ARREGLO_H__\\ #define __ARREGLO_H__\\ #define MAX_ELEM 1000\\ template class Arreglo {\\ \ T arreglo [MAX_ELEM];\\ \ public:\\ \ Arreglo(); //constructor default\\ \ Arreglo( const Arreglo& original); //constructor de copia\\ \ Arreglo& operator = (const Arreglo& original);\\ \ operator int() const;\\ \ const T& operator[] (unigned pos) const;\\ \ T& operator[] (unigned pos);\\ };\\ /* El operador << debe estar declarado en un ambito global */\\ template ostream& operator << (ostream& os, const Arreglo& arreglo);\\ /* aca irían las definiciones que por ser una clase **template** se deben hacer en el **.H***/\\ #endif''