====== 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''