MAIN #include <stdio.h> #include <stdlib.h> #include "tarea1.c" //ejecucion y pruebas int main(){ printf("\nSe adicionan los siguientes numeros al arbol\n"); arbol* Manzano = new_arbol(&ComparaPorBits); int n = 10; printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n)); add_value(Manzano,n); n = 20; printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n)); add_value(Manzano,n); n = 4; printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n)); add_value(Manzano,n); n = 7; printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n)); add_value(Manzano,n); n = 0; printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n)); add_value(Manzano,n); n = 15; printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n)); add_value(Manzano,n); n = 30; printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n)); add_value(Manzano,n); n = 50; printf("Agregamos %d que tiene %d bits\n",n,BitsEncendidos(n)); add_value(Manzano,n); printf("------------------------\n"); printf("El arbol queda:\n"); print_arbol(Manzano); printf("\nla funcion map con \"Sumar\" daría: %d\n\n",map(Manzano->values,&Sumar)); free_arbol(Manzano); } .H typedef struct nodo { int val; struct nodo *left; struct nodo *right; } nodo; typedef struct arbol { nodo *values; int (*func)(int,int); } arbol; arbol *new_arbol(int (*func)(int,int)); void add_value(arbol *a, int v); nodo *print_arbol(arbol *a); int map(nodo *n, int (*func)(int,int,int)); void free_arbol (arbol *a); //Funciones Auxiliares int ComparaPorBits(int a,int b); int BitsEncendidos(int a); int Sumar(int a,int b,int c); void free_nodo (nodo *a); void ImprimeNodo(nodo *a,int n); .C #include <stdio.h> #include <stdlib.h> #include "tarea1.h" //implementacion de funciones propuestas arbol *new_arbol(int (*func)(int,int)){ arbol* tree; tree = (arbol *)malloc(sizeof(arbol)); if(tree==NULL) return tree; tree -> values = NULL; tree -> func = func; return tree; } void add_value(arbol *a, int v){ if(a->values==NULL){ a -> values = (nodo *)malloc(sizeof(nodo)); a -> values -> val = v; a -> values -> left = NULL; a -> values -> right = NULL; return ; } nodo* b = a->values; nodo* c = b; while(b!=NULL){ if(a->func(v,b->val)<1){ c = b; b = b->left; }else{ c = b; b = b->right; } } nodo* d = (nodo *)malloc(sizeof(nodo)); d -> val = v; d -> left = NULL; d -> right = NULL; if(a->func(v,c->val)<1){ c->left = d; }else{ c->right = d; } } //Función auxiliar de impresion de nodos void ImprimeNodo(nodo *a,int n){ int i; for(i=0;i<n;i++){printf("\t");} printf("-%d-\n",a->val); if(a->left!=NULL){ ImprimeNodo(a->left,++n); }else{ ++n; for(i=0;i<n;i++){printf("\t");} printf("-*-\n"); } if(a->right!=NULL){ ImprimeNodo(a->right,n); }else{ for(i=0;i<n;i++){printf("\t");} printf("-*-\n"); } } nodo *print_arbol(arbol *a){ printf("\n"); ImprimeNodo(a->values,0); printf("\n"); return a->values; } //El arbol se imprime mostrando la raiz en el //primer nivel, luego en el segundo nivel se //muestra primero el hijo izquierdo y luego //el derecho, asi recursivamente. //Funcion borrado auxiliar void free_nodo (nodo *a){ if(a->left!=NULL) free_nodo(a->left); if(a->right!=NULL) free_nodo(a->right); free(a); } void free_arbol (arbol *a){ if(a->values!=NULL) free_nodo(a->values); free(a); } //Funciones auxiliares para map int Sumar(int a,int b,int c){ return a+b+c; } int map(nodo *n, int (*func)(int,int,int)){ if(n->left==NULL && n->right==NULL) return n->val; if(n->left==NULL && n->right!=NULL) return func(n->val,map(n->right,func),0); if(n->left!=NULL && n->right==NULL) return func(n->val,map(n->left,func),0); return func(n->val,map(n->right,func),map(n->left,func)); } //función para obtener numero de bits encendidos int BitsEncendidos(int a){ int total=0; int i=0; int b=a; while(b!=0){ while(b%2==0){ b=b/2; ++i; } ++total; --b; } AUX 1 Pregunta 1: Implemente un programa equivalente al comando wc, que permita contar el número de líneas, palabras y caracteres de un input. Pregunta 2: 1. Escriba una función char * reverse(char *s) que recibe un string de argumento y retorna el string invertido, usando punteros y no subíndices (no debe modificar el string original y debe usar memoria dinámica para el resultado) 2. Escriba una función void reverse(char *s) que recibe un string de argumento y lo modifica de forma de invertirlo en el mismo lugar, sin pedir más memoria. Pregunta 3: Escriba un programa que imprime los argumentos de una función y el número correspondiente. Ejemplo: ./programa a b c Nuestro ejecutable se El argumento número 1 El argumento número 2 El argumento número 3 llama ./programa. es a. es b. es c. ANS P1 #include <stdio.h> #define IN 1 /* estamos dentro de una palabra */ #define OUT 0 /* estamos fuera de una palabra */ int main(){ int c, nl, np, nc, state; state = OUT; nl = np = nc = 0; while((c = getchar()) != EOF){ ++nc; /* agrego un caracter */ if(c== '\n') /* nueva linea */ ++nl; if(c == ' ' || c == '\n' || c == '\t') /* estoy fuera de una palabra */ state = OUT; else if (state == OUT){ /* si estoy afuera y veo un caracter, entro a la palabra */ state = IN; ++np; } } printf("%d %d %d\n", nl, np, nc); } P2 #include <stdio.h> #include <stdlib.h> #include <string.h> char *reverse1(char *s) { char *p, *s2; /* siempre lo primero, pedir memoria */ /* +1 por el 0 final */ p = (char *)malloc(strlen(s)+1); /* s2 a la ultima posicion */ s2 = p+strlen(s); /* pongo el 0 correspondiente y me muevo */ *s2-- = 0; /* vamos iterando */ while(*s) /* es lo mismo que != 0 -> termina cuando llego al 0 del final */ *s2-- = *s++; return p; } void reverse2(char *s) { char *p; char aux; /* pongo el puntero p en la ultima posicion menos el 0 */ p = s+strlen(s)-1; while(p>s) { /* cuando se cruzan es que terminé de invertirlos */ aux = *s; /* guardamos primer caracter en el auxiliar */ *s++ = *p; /* copiamos en el primero el del final */ *p-- = aux; /* copiamos el auxiliar al final */ } } int main(){ char *str = "hola curso"; char *str2 = reverse1(str); printf(" original: %s \n invertido: %s \n", str, str2); reverse2(str2); printf(" invertido de invertido: %s \n", str2); free(str2); /* acordarse de liberar la memoria! */ return 0; } P3 #include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]){ /*argc es el numero de argumentos, argv es un arreglo de strings (char *) */ int i; printf("Nuestro ejecutable se llama %s. \n", argv[0]); /* argv[0] siempre es el nombre de nuestro ejecutable*/ for (i=1; i < argc ; i++){ printf("El argumento número %d es %s. \n", i, argv[i]); } return 0; } EXTRAS PUNTEROS #include <stdio.h> int main(){ char *p = "hola"; /* & -> la direccion de lo apuntado */ printf("direccion de p? %p \n", &p); /* qué significa que p sea un puntero? :O */ printf("lo que hay en p? %p \n", p); /* *p es lo que hay en el lugar apuntado! si lo interpretamos como int será 'h' en ascii */ printf("lo que hay en el lugar apuntado por p? %d \n", *p); /* o como un string, que nos dará todo el string hasta el 0 */ printf("lo que hay en el lugar apuntado por p? %s \n", (char *)p); int i= 10; /* podemos sacar la direccion de un int también */ printf("direccion de i? %p \n", &i); /* pero dentro no hay un puntero, hay directamente un 10 */ printf("lo que hay en i? %d \n", i); return 0; } STRING #include <stdio.h> #include <stdlib.h> #include "string.h" int main(){ char string[29] = "hola"; char *str1 = string; printf("el string es %s \n", string); printf("size string: %d, size *str: %d, length string: %d, length *str: %d \n", (int)sizeof(string), (int)sizeof(str1), (int)strlen(string), (int)strlen(str1)); int arreglo[] = {6, 5, 4, 3, 2, 1}; int *ptr; int i; ptr = &arreglo[0]; /* apuntamos al primer elemento del arreglo */ printf("\n\n"); for (i = 0; i < 6; i++) { printf("arreglo[%d] = %d ", i ,arreglo[i]); /*<-- A */ printf("ptr + %d = %d\n", i , *(ptr + i)); /*<-- B */ } /* return 0 y probar hasta acá */ printf("\n\n"); char str[] = "Hola curso!"; char str2[20]; strcpy(str2, str1); printf("El string copiado es %s \n", str2); printf("\n\n"); /* comprarar y concatenar */ char str3[] = "hagamos"; char str4[] = "una prueba"; if(!strcmp(str3,str4)) /* == (strcmp(str3,str4) == 0)*/ printf("Strings iguales \n"); else printf("Strings son distintos \n"); printf("\n\n"); char string5[22] = "hagamos "; /* probar con 10 y ver que se cae */ char string6[] = "otra prueba!\n"; printf("%s\n", string5); strcat(string5, string6); printf("%s\n", string5); printf("\n\n"); return 0; } AUX 2 Pregunta 1: Implemente un TDA diccionario usando lista enlazada y árboles binarios, y compare ambas implementaciones usando entradas ordenadas y desordenadas. Pregunta 2 - C1 Primavera 2010: Se le pide escribir un programa que verifique si la entrada estándar tiene los paréntesis balanceados. Los paréntesis son “(,{,[” para abrir y “),},]” para cerrar. Para esto utilice siguiente implementación de pila: typedef struct nodo { char val; struct nodo *next; } stack; stack *create_stack() { stack *res = (stack *)malloc(sizeof(stack)); res->next = NULL; } int is_empty(stack *st) { if (st == NULL || st->next == NULL) return 1; return 0; } 1 void free_stack(stack *st) { if (st == NULL) return; free_stack(st->next); free(st); } Usted debe implementar la función put y get, y el programa que utiliza la pila para verificar el balanceo de paréntesis. ANS STACK #include <stdio.h> #include <stdlib.h> typedef struct nodo { char val; struct nodo *next; } stack; stack *create_stack() { stack *res = (stack *)malloc(sizeof(stack)); res->next = NULL; return res; } void put(stack *st, char val) { stack *res = (stack *)malloc(sizeof(stack)); res->val = val; res->next = st->next; st->next = res; } char get(stack *st) { stack *aux = NULL; if (st == NULL || st->next == NULL) return EOF; char res = st->next->val; aux = st->next; st->next = st->next->next; free(aux); return res; } int is_empty(stack *st) { if (st == NULL || st->next == NULL) return 1; return 0; } void free_stack(stack *st) { if (st->next == NULL) return; free_stack(st->next); free(st); } int main(int argc, char *argv[]) { stack *st; char c; int non = 0; st = create_stack(); while ((c = getchar()) != EOF && !non) { /*print_stack(st);*/ switch (c) { case '(': put(st,c); break; case '{': put(st,c); break; case '[': put(st,c); break; case ')': if (get(st) != '(') non = 1; break; case '}': if (get(st) != '{') non = 1; break; case ']': if (get(st) != '[') non = 1; break; default: ; } } if (!is_empty(st) || non) printf("La entrada no tiene los parentesis balanceados\n"); else printf("La entrada tiene los parentesis balanceados\n"); free_stack(st); return 0; } DICT LISTA #include <stdio.h> #include <stdlib.h> #include "dict-lista.h" /* * Tipo diccionario, implementado con listas enlazadas */ /* * El primer elemento es una cabecera de lista que NO SE USA */ DICT *init_dict() { DICT *p; p = (DICT *)malloc(sizeof(DICT)); if(p == NULL) { fprintf(stderr, "No mem!\n"); exit(1); } p->val = NULL; p->next = NULL; p->llave = NULL; return p; } void add_dict(DICT *d, char *llave, void *val) { DICT *p, *q; for(p = d; p->next != NULL && strcmp(p->next->llave, llave) < 0 ; p=p->next) ; if(p->next != NULL && strcmp(p->next->llave, llave) == 0) p->next->val = val; else { q = (DICT *)malloc(sizeof(DICT)); q->val = val; q->llave = llave; q->next = p->next; p->next = q; } } void *search_dict(DICT *d, char *llave) { DICT *p; for(p = d; p->next != NULL && strcmp(p->next->llave, llave) < 0 ; p=p->next) ; if(p->next == NULL || strcmp(p->next->llave, llave) != 0) return NULL; return p->next->val; } void apply_dict(DICT *d, void (*f)(char *llave, void *val)) { DICT *p; for(p = d->next; p != NULL; p=p->next) f(p->llave, p->val); } void stats_dict(DICT *d) { int cnt = 0; DICT *p; for(p = d->next; p != NULL; p=p->next) cnt++; printf("DICT lista nodos = %d\n", cnt); } DICT ABB #include <stdio.h> #include <stdlib.h> #include <math.h> #include "dict-abb.h" /* * Tipo diccionario, implementado con Arboles Binarios de Busqueda */ /* * Todas las funciones _abb son internas de la implementacion * y son llamadas por la interfaz oficial de DICT */ DICT *init_dict() { DICT *p; p = (DICT *)malloc(sizeof(DICT)); if(p == NULL) { fprintf(stderr, "No hay memoria!\n"); exit(1); } p->head = NULL; return p; } /* * Inserta un par en un ABB * y retorna el nuevo ABB (con el par ya insertado) */ TREE *add_abb(TREE *t, char *llave, void *val) { TREE *q; int cmp; if(t == NULL) { /* Insertar en un arbol vacio */ q = (TREE *) malloc(sizeof(TREE)); if(q == NULL) { fprintf(stderr, "No hay memoria!\n"); exit(1); } q->llave = llave; q->val = val; q->left = q->right = NULL; return q; } cmp = strcmp(llave, t->llave); if(cmp < 0) t->left = add_abb(t->left, llave, val); else if(cmp == 0) t->val = val; else t->right = add_abb(t->right, llave, val); return t; } void *search_abb(TREE *t, char *llave) { int cmp; if(t == NULL) return NULL; cmp = strcmp(llave, t->llave); if(cmp < 0) return search_abb(t->left, llave); else if(cmp == 0) return t->val; else return search_abb(t->right, llave); } void apply_abb(TREE *t, void (*f)(char *llave, void *val)) { if(t == NULL) return; apply_abb(t->left, f); f(t->llave, t->val); apply_abb(t->right, f); } int nodos_abb(TREE *t) { if(t == NULL) return 0; return(nodos_abb(t->left)+nodos_abb(t->right)+1); } int max(int a, int b) { return (a > b) ? a : b; DICTLISTA.H /* * Tipo diccionario, implementado con listas enlazadas */ typedef struct dict_lista { char *llave; void *val; struct dict_lista *next; } DICT; DICT *init_dict(); void add_dict(DICT *d, char *llave, void *val); void *search_dict(DICT *d, char *llave); void apply_dict(DICT *d, void (*f)(char *llave, void *val)); void stats_dict(DICT *d);\ AUX 3 Pregunta 1 - C1 Primavera 2007 Se quiere implementar un árbol binario con la representación entera hasta de 8 bits, para traducir strings de bits. Los 0s van hacia la izquierda y los 1s a la derecha. Debe utilizar la siguiente estructura: typedef struct bin { struct bin *izq, *der; unsigned char val; } ARBOL; Se le pide escribir una función que, usando este árbol para 8 bits, traduzca un string de ceros y unos a un número entero. El string debe tener un máximo de 8 bits para que la función lo transforme en un char sin signo: unsigned char bin2int(char *s, ARBOL *l); Escriba también la función que construye el árbol para n bits: ARBOL *construye_arbol(int val, int n); Suponga que malloc siempre funciona y que los parámetros son correctos. Ejemplo: l = construye_arbol(0, 8); printf("\%d\n", bits2char("11111111", l); Debiera imprimir 255. 1 Pregunta 2 Para verificar errores de transmisión, se usa un bit de paridad que indica si el número de bits en uno de una secuencia es par o impar. Se le pide implementar dos funciones que permitan manejar bits de paridad en un byte, suponiendo que los 7 bits de orden inferior son datos y el bit 8 de orden superior es un bit de paridad. La regla es: si el número de bits en uno de los 7 inferiores es par, el octavo bit debe ir en 1. Si es impar debe ir en 0. unsigned charset_parity(unsigned char c); int check_parity(unsigned char c); Pregunta 3 Se desea aprovechar las capacidades de multicore de los actuales procesadores para escribir un programa que calcule el F ibonacci(n). Primero escriba un programa sin threads (o con 1 thread) y luego multithread. ANS P1 #include <stdlib.h> #include <stdio.h> typedef struct bin{ struct bin *izq, *der; unsigned char val; } ARBOL; ARBOL *construye_arbol(int val, int n){ ARBOL *p; if (n < 0) return NULL; p = (ARBOL *)malloc(sizeof(ARBOL)); p->val = val; p->izq = construye_arbol(val<<1, n-1); p->der = construye_arbol((val<<1)|1, n-1); return p; } unsigned char bin2int(char *s, ARBOL *l){ if(l==NULL){ printf("llegue a null"); return 0; } if (*s == '\0'){ printf("ret: %d \n", l->val); return l->val; } if (*s == '0'){ printf("0: %d \n", l->izq->val); return bin2int(++s, l->izq); } if (*s == '1'){ printf("1: %d \n", l->der->val); return bin2int(++s, l->der); } } int main(){ ARBOL *l = construye_arbol(0, 8); int x = bin2int("11111111", l); free(l); printf("%d\n",x); return 0; } P2 #include <stdio.h> unsigned char set_parity(unsigned char c){ int parity = 0x80; int i; /*1. mascara c c/r 1er bit: c&0x01 */ /*2. desplazarla: (c&0x01)<<i*/ /*3. ponerlo en el bit de paridad: <<(7-i)*/ for (i=0; i<7; i++) parity ^= (c&0x01<<i)<<(7-i); return parity|(c&0x7f); /*0111 1111*/ } int check_parity(unsigned char c){ int parity = 0x80, check, i; for(i=0; i<7; i++) parity ^= (c&0x01<<i)<<(7-i); check = c & 0x80; /* 1000 0000*/ printf("c = 0x%x, check = 0x%x, parity = 0x%x", c, check, parity); return !(parity ^ check); } int main(){ char c = 0x77; /*0111 0111*/ printf("set_parity : &x \n", set_parity(c)); if(check_parity(set_parity(c))) printf ("paridad ok\n"); return 0; } P3 #include <stdio.h> #include <pthread.h> int fibonacci(int n){ if (n==0) return 0; else if (n==1) return 1; else return fibonacci(n-1)+fibonacci(n-2); } void fib_thread(int *value){ int *p=value; *p = fibonacci(*value); } void fib_multi(int *value){ int *p = value; printf("thread trabajando con %d\n", *value); if(*value == 0){ *p = 0; return; } else if(*value ==1){ *p = 1; return; } pthread_t pid1; pthread_t pid2; int prev1 = *value-1; int prev2 = *value-2; pthread_create(&pid1, NULL, (void *)fib_multi, &prev1); pthread_create(&pid2, NULL, (void *)fib_multi, &prev2); pthread_join(pid1, NULL); pthread_join(pid2, NULL); *p = prev1+prev2; return; } int main(){ int value = 10; pthread_t pid; pthread_create(&pid, NULL, (void *)fib_thread, (void *)&value); pthread_join(pid, NULL); printf("resultado 1 thread: %d \n", value); int value2 = 10; pthread_t pid2; pthread_create(&pid2, NULL, (void *)fib_multi, (void *)&value2); pthread_join(pid2, NULL); printf("resultado n thread: %d \n", value2); return 0; } EXTRAS THREADS #include <stdio.h> #include <pthread.h> int main(){ pthread_t f1_thread, f2_thread; void *f1(), *f2(); int i1 = 1; int i2 = 2; pthread_create(&f1_thread,NULL,f1,&i1); pthread_create(&f2_thread,NULL,f2,&i2); pthread_join(f1_thread,NULL); pthread_join(f2_thread,NULL); return 0; } void *f1(int *x){ int i=*x; sleep(1); printf("f1: %d\n",i); pthread_exit(0); } void *f2(int *x){ int i=*x; printf("f2: %d\n",i); pthread_exit(0); } BITS #include <stdlib.h> #include <stdio.h> int main(){ unsigned char a = 1; /*0000 0001*/ unsigned char b = 31; /*0001 1111*/ a ^=b; printf("a^b = %d\n", a); return 0; } AUX 4 Auxiliar N◦4 - Control 1 Profesor: José Miguel Piquer Auxiliar: Javiera Born 18 de abril de 2012 Pregunta 1 - Control 1 Otoño 2011 Parte I Implemente una función: int binary("1010111101"); Que retorna el entero correspondiente a ese número binario. Suponga que el string viene correcto y que el entero cabe en esta arquitectura. Parte II ¿Qué hace esta función?: int f() { int l=1; int i; for(i=0; l != 0; i++) l = l << 1; return i; } Parte III Implemente una función: int rev_endian(int n); Que debe retornar el entero n representado en el endian inverso que esta arquitectura: suponga que sólo existen big endian y little endian. Debe funcionar para cualquier tamanõ de los enteros, o sea, ser portable a cualquier arquitectura. 1 Pregunta 2 - Control 1 Otoño 2011 Parte I Se propone implementar un BOX con dos caracteres de capacidad en vez de solo uno. Para ello usamos dos variables en la caja y dos punteros que indican cual es la variable de donde leer y cual de donde escribir. La sincronización se debe realizar usando dos mutexes por variable, uno para escribir y otro para leer. Se les propone el siguiente código, donde sólo falta agregar los mutexes para sincronizar. typedef struct { char c1, c2; char *in, *out; pthread_mutex_t vacio1, lleno1, vacio2, lleno2; } BOX; BOX *createbox(){ BOX *b; b = (BOX *)malloc(sizeof(BOX)); pthread_mutex_init(&b->vacio1, NULL); pthread_mutex_init(&b->vacio2, NULL); pthread_mutex_init(&b->lleno1, NULL); pthread_mutex_init(&b->lleno2, NULL); pthread_mutex_lock(&b->lleno1); /* Partimos con lleno tomado */ pthread_mutex_lock(&b->lleno2); /* Partimos con lleno tomado */ b-> in = b-> out = &b-> c1; return(b); } void putbox(BOX *b, char c) { if(b->in == &b->c1) { b->c1 = c; b->in = &b->c2; } if(b->in == &b->c2) { b->c2 = c; b->in = &b->c1; } } 2 char getbox(BOX *b){ char c; if(b->out == &b->c1) { c = b->c1; b->out = &b->c2; } if(b->out == &b->c2) { c = b->c2; b->out = &b->c1; } return(c); } Modifique el código para que funcione para un productor y un consumidor. Revise si funciona bien, y explique. Luego revise si funciona para N productores y N consumidores y proponga modificaciones si no funciona. Parte II Vimos en clases que una solución de sincronización con busy wait era una pésima solución. Sin embargo, el profesor ejecutó un productor y un consumidor y resultaba más eficiente que con mutexes. Explique por qué sigue siendo cierto que busy wait es una pésima solución. Pregunta 3 - Control 3 Otoño 2009 Se propone la siguiente solución a N buffers para múltiples productores y consumidores: void putbox(BOX *b, char c) { pthread_mutex_lock(&b->mutex); sem_wait(&b->vacios); sem_post(&b->llenos); b->buf[b->in] = c; b->in = (b->in+1)%NBUFS; pthread_mutex_unlock(&b->mutex); } 3 char getbox(BOX *b){ char c; pthread_mutex_lock(&b->mutex); sem_wait(&b->llenos); sem_post(&b->vacios); c = b->buf[b->out]; b->out = (b->out+1)%NBUFS; pthread_mutex_unlock(&b->mutex); return(c); } Comente si está correcta, si permite paralelismo entre productores y consumidores y si no genera deadlocks. Explique su análisis y haga las menos correcciones posibles que generen una solución correcta. 4 ANS P1 #include <stdio.h> /* PARTE 1 */ int binary(char *s) { int res = 0; /*iniciamos el contador*/ while(*s != 0) { /* vamos leyendo el string*/ res <<= 1; /* shifteamos lo que ya llevamos */ if(*s == '1') res = res+1; /*si es 1, cambiamos el 1 al final*/ s++; } return res; } /* * ej: binary('1001') * 1. res= 0, *s=1 -> res = 1; * 2. res= 1 <<= res=10, *s=0 -> res = 10; * 3. res=10 <<= res=100, *s=0 -> res = 100; * 4. res=100 <<= res=1000, *s=1 -> res = 1001; * 5. return res (como int). */ /* PARTE 2 */ int f() { int l=1; int i; for(i=0; l != 0; i++) l = l << 1; return i; } /*Analicemos por partes qué es lo que hace: * for: * i=0: l=1. * i=1: l=10. * i=2: l=100 * ... * i=n: l=000..00 (esto ocurrirá cuando el 1 haga overflow!) * end * => n nos dará el número de bits de 'int' en la arquitectura! */ /* PARTE 3 */ int rev_endian(int n) { unsigned char *cp1, *cp2; /* trabajamos con unsigned para * asegurar buen comportamiento */ int ret = 0; /*donde almacenaremos el resultado */ int i; /* contador */ cp1 = (unsigned char *) &n; /* puntero al n: será a su 1er bit */ cp2 = (unsigned char *) &ret + sizeof(ret) - 1; /* puntero al último bit de ret */ for(i=0; i < sizeof(ret); i++) *cp2-- = *cp1++; /*copiamos cada bit del principio de n al final de ret y avanzamos */ return ret; } int main() { /* hacemos un pequeño main para probar nuestras funciones */ char *s = "1001"; int a = binary(s); int b = f(); int c = rev_endian(1); /*Con esto podemos ver cual es el máximo: el resultado será 16777216, o en binario, 1 0000 0000 0000 0000 0000 0000 :D */ printf("binary = %d, f = %d, rev_endian = %d", a, b, c); return 0; } P2 /* PARTE 1 */ void putbox(BOX *b, char c) { if(b->in == &b->c1) { /* usaremos los mutex de la variable 1 */ /* primero bloqueamos vacio */ pthread_mutex_lock(&b->vacio1); b->c1 = c; /* y ahora desbloqueamos lleno */ pthread_mutex_unlock(&b->lleno1); b->in = &b->c2; } /* Hacemos lo mismo para la otra variable */ if(b->in == &b->c2) { pthread_mutex_lock(&b->vacio2); b->c2 = c; pthread_mutex_unlock(&b->lleno2); b->in = &b->c1; } } char getbox(BOX *b){ char c; if(b->out == &b->c1) { pthread_mutex_lock(&b->lleno1); c = b->c1; pthread_mutex_unlock(&b->vacio1); b->out = &b->c2; } if(b->out == &b->c2) { pthread_mutex_lock(&b->lleno2); c = b->c2; pthread_mutex_unlock(&b->vacio2); b->out = &b->c1; } return(c); } /* Esta solucion funciona para 1 productor y 1 consumidor, porque no hay paralelismo al poner y sacar datos: * cuando uno escribe en c1, el otro lee en c2, y viceversa. * Con N productores y N consumidores no va a funcionar por haber concurrencia sobre c1 y c2. * Para arreglar esto, es necesario tener un mutex para put y otro para get, al entrar y salir de cada funcion. */ /* PARTE 2*/ /* Busy Wait es una pésima solución por consumir una cantidad altísima de CPU al estar constantemente preguntando por el bloqueo. * Si cada bloqueo es corto, entonces puede resultar eficiente en tiempo de ejecución, pero igual gastará mucho procesador. *Si el bloqueo es largo, entonces es terrible en todo sentido, pues utilizará el 100% del procesador en forma totalmente inútil. */ P3 /* Podemos ver una diferencia fundamental entre el wiki y el codigo propuesto: * estamos usando el mismo mutex para put y get. * Como este mutex es compartido, generamos un deadlock, ya que si nos bloqueamos en un wait * el otro thread no podrá desbloquearnos, pues no podrá tomar el mutex. * Entonces, debemos separar los mutex en 2 (put y get) */ void putbox(BOX *b, char c) { pthread_mutex_lock(&b->mutex_put); sem_wait(&b->vacios); sem_post(&b->llenos); b->buf[b->in] = c; b->in = (b->in+1)%NBUFS; pthread_mutex_unlock(&b->mutex_put); } char getbox(BOX *b){ char c; pthread_mutex_lock(&b->mutex_get); sem_wait(&b->llenos); sem_post(&b->vacios); c = b->buf[b->out]; b->out = (b->out+1)%NBUFS; pthread_mutex_unlock(&b->mutex_get); return(c); } /* Ahora tenemos otro error: hacemos un post de lleno antes de poner el dato * luego puede despertar un get y sacar un dato aún no escrito (si in == out), y viceversa. * Para arreglar esto debemos mover el post después del código que pone/saca el dato * y como in/oyt no se comparte entre prod y cons, podemos postergarlo (la proteccion entre * ellos ya está dada por el mutex) */ void putbox(BOX *b, char c) { pthread_mutex_lock(&b->mutex_put); sem_wait(&b->vacios); b->buf[b->in] = c; sem_post(&b->llenos); b->in = (b->in+1)%NBUFS; pthread_mutex_unlock(&b->mutex_put); } char getbox(BOX *b){ char c; pthread_mutex_lock(&b->mutex_get); sem_wait(&b->llenos); c = b->buf[b->out]; sem_post(&b->vacios); b->out = (b->out+1)%NBUFS; pthread_mutex_unlock(&b->mutex_get); return(c); } /* Ahora tendremos que efectivamente no hay deadlocks y hay buen paralelismo! */