Cátedra: Veiga
Fecha: 1er Cuatrimestre 2006
Día: 25/07/2006
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<T> 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.
#include <cstring>
#include <windows.h>
#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;
}
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;
}
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;
}
/* 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;
}
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.
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.
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.
#ifndef ARREGLO_H__
#define ARREGLO_H__
#define MAX_ELEM 1000
template <class T> class Arreglo {
T arreglo [MAX_ELEM];
public:
Arreglo(); constructor default
Arreglo( const Arreglo<T>& original); constructor de copia
Arreglo<T>& operator = (const Arreglo<T>& original);
operator int() const;
const T& operator[] (unigned pos) const;
T& operator[] (unigned pos);
};
/* El operador « debe estar declarado en un ambito global */
template <class T> ostream& operator « (ostream& os, const Arreglo<T>& arreglo);
/* aca irían las definiciones que por ser una clase template se deben hacer en el .H*/
#endif