No es un bug, es una característica no documentada

30/9/15

Servicios y procesos. Procesos en C (II). PIPE

PIPE

Las PIPE (tuberías) son un mecanismo para poner en comunicación los procesos padre e hijo.
Se comporta como un falso fichero en el que ambos pueden leer y escribir.

Conceptualmente hablando, tendremos dos procesos, padre e hijo. Entre ellos se creará una tubería que emplearán para leer y escribir.
Para ello usaremos un array de enteros de dos posiciones. El [0] será de lectura, y el [1] de escritura. Es bidireccional pero sólo puede usarse en uno de los dos sentidos.

Si necesitamos una comunicación que circule en los dos sentidos, habrá que crear dos PIPE, uno para cada dirección.

Para poder utilizar este método de comunicación deberemos cargar la librería unistd, y tener en cuenta que se escribe como los ficheros, usando la función write y read.

Veamos un código de ejemplo para pillar la idea.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void main(){

     int fd[2];
     char buffer[30];
     pid_t pid;

     //#include<unistd.h>
     // int pipe(int fd[2]);
     // fd[0] contiene el descriptor para lectura

     pipe(fd); // Se crea el PIPE
     pid = fork();

     switch(pid){
     
          case -1: // Error
                printf("No se ha podido crear un hijo \n");
                exit(-1);
                break;
          case 0: // Hijo
                close(fd[0]); // Cierra el descriptor que no va a usar. El de lectura
                printf("El hijo escribe en el PIPE... \n");
                write(fd[1], "Hola papi", 10);
                break;
          default: // Padre
                close(fd[1]); // Cierra el descriptor de escritura
                wait(NULL); // Espera a que finalice el hijo
                printf("El padre lee el PIPE \n");
                read(fd[0], buffer, 10);
                printf("\t Mensaje leido: %s \n", buffer);
     }
}
En el código podemos ver que después de la declaración de cada proceso, tenemos una lína que reza:
close(fd[1]);
Con esto lo que hacemos es cerrar la parte de la tubería que no vamos a utilizar. Me explico, si el que escribe es el hijo, en su lado cerraremos la posición cero, y si el padre es el que va a leer, cerraremos la posición 1. Así conseguiremos algo más de seguridad en nuestro programa. Es una práctica recomendable, aunque es verdad que nuestro código funcionará exactamente igual sin hacerlo.

Ejercicio. Haz tres procesos (padre, hijo y nieto) que se comuniquen entre ellos a través de PIPEs.

Solución.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void main(){

     int fd1[2], fd2[2];
     char buffer[30], buffer2[30];

     pid_t pid, pidNieto;

     pipe(fd1);
     pipe(fd2);

     pid = fork();

     switch(pid){

          case -1: // Error
                printf("Ha habido un error \n");
                exit(-1);
                break;
          case 0: // Hijo
                close(fd1[0]);
                printf("Escribe el padre: \n");
                write(fd1[1], "El padre dice hola", 20);

                //Creación de nieto
                pidNieto = fork();

                switch(pidNieto){
                     case -1: // Error
                          printf("Ha habido un error \n");
                          exit(-1);
                          break;
                     case 0:
                          close(fd2[0]);
                          printf("Escribe el nieto \n");
                          write(fd2[1], "Soy el nieto", 13);
                          break;
                     default:
                          close(fd2[1]);
                          wait(NULL);
                          printf("El padre lee \n");
                          read(fd2[0], buffer2, 13);
                          printf("Mensaje leído: %s", buffer2);
                          break;
                }
                break;
          default: // Padre
                close(fd1[1]);
                wait(NULL); // Espero que finalice el nieto
                printf("\nEl abuelo lee: \n");
                read(fd1[0], buffer, 20);
                printf("Mensaje leído: %s \n", buffer);
                break;
     }

}

29/9/15

Servicios y procesos. Procesos y C (I)

¿Qué es un proceso?

Proceso = Programa en ejecución

Cada una de las CPU se tienen que compartir a ratos con todos los procesos cargados en la memoria RAM.

Cuando un programa usa la CPU y sale, hay que hacer una especie de instantánea para guardar el contador de procesos pendientes, donde se ha quedado, etc.

Esto se conoce como el BCP (bloque de control de procesos). Es una tabla del sistema operativo que guarda la información de la situación de como se había quedado el programa en el momento de finalizar su tiempo en la CPU y dejar espacio a otro proceso.

Estados del proceso

Un proceso puede estar en la CPU, es decir, estará en ejecución.
Puede ser que esté cargado en la RAM, preparado para que el SO le de paso a la CPU. Estará listo.

O puede ser que esté esperando a utilizar los recursos que otro proceso ha cogido y hasta que no finalice el sistema operativo no le va a dejar continuar. Entonces estará bloqueado.


La contienda es como se llama a la pugna que hacen los procesos listos para conquistar la CPU.

Hay distintos modos de realizar la asignación de la contienda. Entre otros:
è Round-Robin. Método circular
è Por prioridades. Es decir, el antivirus tendrá más prioridad que la calculadora, por ejemplo. O el Word al estar tecleando conseguirá más prioridad de la ventana activa para no dar sensación de lentitud o ir a saltitos… Pero esto tiene varios problemas, como la inacción. Es decir, si mientras P1 (proceso 1) está en ejecución por ganar a la P2 pero entra P3 que tiene mayor prioridad, saldrá P1 y ganará la contienda P3.
è Por tiempos. Mayor prioridad el que menor tiempo estimado tiene para terminar.

Eso sí, al programar no podremos controlar los métodos de ordenación de la contienda. No podemos garantizar que los procesos vayan a coger la CPU en el momento que vayamos a querer.

Procesos en los SSOO

Para ver los procesos en Windows, iremos al Administrador de Tareas à Procesos


Para verlos desde la línea de comandos, en CMD escribiremos tasklist. Además al hacerlo por línea de comandos veremos el PID, el identificador del proceso.


En Ubuntu podemos verlo en la terminal con el comando ps.


Si hacemos ps –f también aparecerá el PPID, el identificador del proceso padre.


Con ps –AF aparecen todos los procesos lanzados en el sistema.

PID y procesos en C

Vamos a realizar las primeras prácticas con los procesos, los PID y los PPID en el lenguaje C. Para ello hemos instalado un entorno VitaLinux que trae ya incorporado el compilador gcc, pero podéis utilizar cualquier herramienta de vuestra elección que os permita trabajar programando en C.

EXECL
Execl sirve para ejecutar comandos del sistema y cualquier programa. Los argumentos son (const char *fichero, cons char *arg0, …, char *argN, (char*)NULL).
Devolverá -1 si hay condición de error.

Veamos un código de ejemplo
#include <stdio.h>
#include<unistd.h>

void main(){
     printf(“Los archivos del directorio son: \n”);
     execl(“/bin/ls”, “ls”, “-l”, (char *)NULL);
     printf(“ERROR!!!”);
}
Aquí estaremos haciendo un ls –l para ver todos los archivos del directorio desde donde ejecutemos este programa.

System

A diferencia de execl, system ejecutará sólo comandos del sistema, como podemos ver abajo. Vamos a ver el siguiente programa para hacernos una idea.
#include <stdio.h>
#include <stdlib.h>

void main(){
     system(“ls –l > ficSalida”);
     printf(“FIN”);
}
Lo que hace el código es guardar el resultado de un ls –l de la carpeta actual del PATH a un fichero salida.

PID

En la arquitectura cliente – servidor tenemos dentro de un servidor web un proceso que está escuchando, en listen. Le hacen una petición y este proceso crea un hijo que sirva la página web al cliente. Una vez finalizada la tarea, el hijo sale de la memoria al finalizar su tarea. Durante todo la ejecución, el proceso padre se ha mantenido activo permaneciendo a la escucha de otras peticiones.

Vamos a ver un programa que nos muestre los identificadores del proceso actual y de su padre.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void main(){
     pid_t id_pactual, id_padre;
     
     id_pactual = getpid();
     id_padre = getppid();

     printf(“PID actual: %d \n”, id_pactual);
     printf(“PID padre: %d \n”, id_padre);
}
Analicemos este código.

  • La línea de declaración pid_t nos indica el tipo de variable que será, una que nos sirva para almacenar el número de proceso que tenemos.
  • La función getpid() devuelve el id del proceso actual
  • Y la función getppid() devuelve el id del padre del proceso actual.
Ahora ya sabemos ver los id de los procesos, pero… ¿cómo se crean los procesos hijos?
Para eso tenemos la instrucción fork(), que es la encargada de crear un proceso hijo. Es decir, una copia exacta del proceso padre, pero a partir de ahora independientes.
Estos dos procesos, junto con todos los del sistema, entrarán en la contienda por la puja de la CPU independientemente. Y por tanto el control de tiempo también será independiente.

Para poder diferenciar uno de otro lo conseguimos con el valor devuelto por fork(). Con un ejemplo se verá más claro.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void main(){

     pid_t pid, hijo_pid;

     pid = fork(); // Aquí crea el proceso hijo
     
     if (pid == -1){
          printf(“Ha habido un error”);
          exit(-1);
     }
     if(pid == 0){
          // Nos encontramos dentro del proceso hijo
          printf("soy el proceso hijo \n\t Mi PID es %d. El PID de mi padre es: %d. \n", getpid(), getppid());
     }
     else{
          hijo_pid = wait(NULL);
          printf("Soy el proceso padre: \n\t Mi PID es %d. El PID de mi padre es: %d. \n\t Mi hijo %d terminó. \n", getpid(), getppid(), pid);
     }
}
Hay varios puntos que comentar. El primero es que como ya hemos dicho, los procesos pese a estar en un mismo programa, tanto el hijo como el padre son independientes en el momento de ejecutar fork().
Si nos devuelve un valor igual a 0, sabremos que estamos tratando con el hijo, mientras que cualquier otro valor que no indique una condición de error nos hará saber que está funcionando el padre.

Dentro del padre tenemos la línea
hijo_pid = wait(NULL);

Con ésta línea indicaremos que va a esperar a la finalización del proceso hijo, y la variable pid guardará el PID del padre.

¿Ha quedado claro? Atrevámonos con un ejercicio sencillico.

Ejercicio. Coged un proceso, cread una variable y guardad un valor. 7, por ejemplo. El proceso crea un hijo que le suma 5, y el padre le resta 5. Visualiza por pantalla el resultado de ambas operaciones así como el PID y el PPID de ambos procesos.

Solución.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

void main(){
     pid_t pid, hijo;
     int n = 7;

     pid = fork();

     if (pid == -1){
          printf(“Error \n”);
          exit(-1);
     }
     if (pid == 0){
          n = n + 5;
          printf("Soy el hijo. Valor de n = %d.\n Proceso %d, padre %d \n\n", n, getpid(), getppid());
     }
     else{
          n = n – 5;
          printf("Soy el padre. Valor de n = %i.\n Proceso %d, padre %d \n\n", n, getpid(), getppid());
     }

}

26/9/15

Desarrollo de interfaces.Instalación de Visual Studio 2012

16:30 Posted by Inazio No comments
 En el desarrollo de interfaces nos ocuparemos de... ¡las interfaces! Que poder de deducción tenéis, jodios.
Bueno, esta aplicación la usaremos para programar en Visual Basic, lenguaje que aprendí a los doce años y lo dejé a los 13 (descubrí el mundo de las redes y los sistemas y me engancharon muchísimo más).

Como fuere, para la instalación ejecutamos el programa, aceptamos los términos y condiciones y si se desea, podemos unirnos al programa para la mejora de la experiencia del usuario (yo no lo he marcado).


Lo siguiente será seleccionar las características a instalar. Desmarcamos las opciones de Blend para Visual Studio, que es el que utilizaríamos para programar en Windows 10 con el Touch, por ejemplo, y LightSwitch, usado para crear herramientas empresariales de una forma bastante rápida.

Desmarcadas ya, pulsamos sobre Instalar.


Y bueno, tenemos paciencia. Comenzará la descarga y aplicación de los módulos correspondientes.


Cuando haya finalizado, podremos iniciar el programa.


Deberemos introducir el serial para activar la aplicación y pulsamos en Siguiente.


Realizada la activación, cerramos para ver el menú principal de la aplicación.


Escogeremos la configuración de entorno predeterminada que corresponda a Visual Basic, que es como vamos a desarrollar, aunque si lo deseamos podremos cambiarlo en cualquier momento yendo a Herramientas - Importar y exportar configuraciones - Restablecer todas las configuraciones.


Y esta será la pantalla inicial, desde la que podremos elegir como programar, o incluso ver videos para aprender como iniciarnos con el entorno de Visual Studio 2012.


Como se programa lo veremos en futuras entregas.

Programación multimedia. Instalación y configuración de Android Studio

En éste módulo aprenderemos a programar aplicaciones para dispositivos móviles (y videojuegos!!! también videojuegos). 

Anteriormente lo hacian instalando plugins en Ecplipse y programando con el mismo, pero éste año vamos a hacerlo con una herramienta que por fin está estable, Android Studio, programa gratuito.

Una vez descargado, lo primero que haremos es lanzar el instalador.


Nos aseguramos que están marcadas los siguientes componentes.


Aceptamos el acuerdo de licencia sin leerlo (no nos engañemos, no ibas a hacerlo de todos modos)


Eliges la ruta de instalación


Y creas la entrada en la carpeta de menú de inicio


Por último, lanzamos el programa al finalizar la instalación.


¿A que no ha sido para tanto? Bueno, vayamos a configurarlo en ese caso

Para empezar, partiendo del caso de que no hayamos usado antes una versión previa de Android Studio, marcamos la siguente casilla de check.


Saltará el aviso del firewall, donde le daremos permiso para redes privadas (pese a lo que ponga en la imagen de abajo)


Y seleccionamos el tema a nuestra elección. Yo elegí el negro porque despúes de llevar mucho rato programando me cansa menos la vista.


Comenzará a descargar los componentes, tened paciencia que según la velocidad de conexión puede tardar un buen rato. En clase costó alrededor de media hora, en mi casa no llegó a cinco minutos...


Cuando finalice la descarga, veremos algo tal que así. Pulsamos en Finish


Y ésta es la pantalla de bienvenida. Para comenzar las cofiguraciones podríamos ir directamente a Configure, pero ya que estamos vamos a hacer un nuevo proyecto y así lo vemos. Pulsa en Start a New Android Studio Project


Le damos un nombre y localización


Marcamos para Phone and Tablet y elegimos la versión mínima del SDK con la que funcionarán nuestras aplicaciones Android.


Pulsa Next y selcciona Blank Activity


Aquí simplemente ponle un nombre a tu actividad y pulsa Next.


Y vuelve a permitir el Firewall en las redes privadas


Nos aparecerá una pantalla de bienvenida con tips. Podemos ocultarla al arrancar si lo deseamos marcando el check de la parte inferior izquierda.


En la parte superior nos encontramos con el menú de acciones a realizar. Si vemos la segunda linea, tenemos un muñeco Android vestido con camisa azul y una flecha descendente. Pulsamos ahí para descargar las versiones del SDK para las que vayamos a programar (Lollipop, KitKat...)


E iremos a parar a esta ventana. Yo voy a desarrollar para las versiones Android 4.2 y 5.0 (más para 4.2 que es con el smartphone con el que realizaré el testeo, pero también la otra por si lo quiero probar en mi movil actual).


Comenzará a descargar los componentes requeridos. Como antes, paciencia dependiendo de tu conexión...


Y cuando finalice veremos la pantalla confirmando la descarga e instalación.


Volvemos al menú de la parte superior, y nos vamos al muñeco android de la izquierda, el que aparece con un display. Este sirve para configurar las opciones de nuestro smartphone y realizar testeos desde la propia aplicación.


Ya tenemos un telefono Nexus configurado de fábrica, pero a no ser que coincida con nuestro modelo, vamos a realizar uno nuevo. Nos vamos a Create Virtual Machine para la configuración. Yo lo haré con un Samsung Galaxy Trend Plus, del que deberé buscar las características por Internet.


Lo primero es seleccionar el Hardware. Lo dicho, tenemos algunas plantillas preconfiguradas, pero lo más facil es que no coincida con nuestro modelo, por lo que si es el caso, pinchamos en New Hardware Profile. 



Aquí rellenamos las opciones de nuestro smartphone. Lo más facil para cerciorarnos de que sean correctas es buscar las características por Internet. San Google, dios te bendiga.


Ahora ya podremos seleccionar nuestro teléfono de la lista. Lo marcamos y pulsamos Next.


Elegimos el SDK correspondiente a nuestro teléfono. Vemos que tenemos procesadores de x86 y arm. Los x86 emulan mejor los smartphone en el programa, pero los arm son la tecnología con la que están montados los propios smartphone. Para gustos... Lo que aconsejo es montar uno con cada uno y realizar pruebas de testeo a ver como responden.

Por cierto, para los x86 deberéis tener activada la virtualización de sistemas Intel en la BIOS, si no os dará problemas a la hora de lanzar el smartphone en esta plataforma.


Comenzará la instalación de los componentes requeridos.


Y al finalizar ya podremos pulsar sobre Finish.


Por último, seleccionamos el SDK para nuestro teléfono y comprobamos que la configuración es la correcta.



Ahora le daremos a Finish y ya tendríamos la emulación de nuestro teléfono configurada. En teoría podríamos empezar ya a programar, pero para obtener los mejores resultados, vamos a instalar un módulo para trabajar con tecnología Intel x86 correctamente.

Para ello, en la ventana principal del proyecto, nos vamos a la gestión de las SDK


Y dentro de ellas, entramos en SDK Tools, desde la que descargaremos la Intel x86 Emulator Acelerator (HAXM Installer) para permitir usar la tecnología de virtualización de Intel.



En teoría ya podríamos arrancar nuestra emulación correcta, pero hay veces que esto falla. Si es nuestro caso, entramos en la BIOS y nos cercioramos que la Tecnología de Virtualización de Intel está activada.

Posteriormente, yo me he tenido que descargar el instalador para la aceleración de hardware, que encontré en el siguiente enlace


Teóricamente es válido para todos los procesadores Intel, pero cercioraros con cada modelo de ordenador que tengáis por si acaso.


Instalamos y ya podemos iniciar la simulación de nuestro Smartphone. Nuevamente desde la ventana de nuestro proyecto accedemos a la sección de ADV Manager


Y arrancamos el dispositivo que hemos estado configurando


El resultado es el siguiente con mi configuración