ERROR USUARIO NO VALIDADO

MÓDULO DE SINCRONIZACIÓN Y COMUNICACIÓN

INTRODUCCIÓN

Este módulo incide fundamentalmente en los servicios POSIX para la sincronización y la comunicación, tanto de procesos ligeros como pesados. Unas veces serán servicios del sistema operativo y otros serán servicios proporcionados a nivel de biblioteca (por ejemplo por la biblioteca pthread).

Se utilizarán los siguientes programas, que deberán descargarse de la web y compilar para su ejecución:

Carreras.c Compart_pth.c Compart_prc.c Concurr_pth.c
Concurr_prc.c CPUs_prc.c CPUs_pth.c Escritor.c
Lector.c TCP_c.c TCP_s.c Times_C.c
UnSegundo.c Ventanilla_pth.c Ventanilla_prc.c Ventanilla_srl.c


Los servicios y funciones de biblioteca utilizados en dichos programas son los siguientes:

accept alarm atoi bind
bzero calloc close connect
execvp exit fcntl fflush
fork fprintf getenv gethostbyname
getpid htons kill listen
lseek memcpy mmap munmap
open perror poll printf
pthread_cancel pthread_cond_destroy pthread_cond_init pthread_cond_signal
pthread_cond_wait pthread_create pthread_join pthread_mutex_destroy
pthread_mutex_init pthread_mutex_lock pthread_mutex_unlock pthread_setcancelstate
pthread_setcanceltype read recv sched_yield
send shutdown signal sizeof
socket strlen sysconf times
toupper usleep wait waitpid
write

CONCURRENCIA

En un sistema UNIX la concurrencia sucede a muchos niveles.

Actualmente, en la mayoría de los sistemas operativos modernos encontramos las siguientes características relacionadas con su capacidad de concurrencia:

  • Sistema multiproceso: el sistema permite lanzar múltiples mandatos o aplicaciones, que, al ejecutar, serán múltiples procesos. Todos los procesos del sistema ejecutarán concurrentemente. El sistema crea la ficción de una CPU (virtual) exclusiva para ejecutar cada proceso. Un sistema puede ser multiproceso incluso cuando sólo dispone de una única CPU. En este último caso, de acuerdo a la planificación del SO, los procesos intercalan su ejecución en la única CPU existente.
  • Sistema multiusuario: múltiples usuarios pueden conectarse y trabajar concurrentemente sobre el sistema.
  • Sistema multiprocesador: el sistema explota todos los recursos de cómputo disponibles. Si la máquina dispone de varias CPUs, ninguna quedará ociosa mientras existan procesos listos para ejecutar. Podrá haber en ejecución paralela real tantos hilos de ejecución como procesadores tenga la máquina. Ciertas tecnologías modernas ofrecen incluso más:
    • HyperThreading permite dos hilos de ejecución por procesador.
    • DualCore encapsula dos procesadores completos en un único Chip.
    • QuadCore encapsula cuatro procesadores completos en un único Chip.
  • Captura de señales: un proceso puede decidir ejecutar una función cuando el sistema notifique un evento dado, vía una determinada señal. La ejecución de la función asociada será asíncrona (y en cierto sentido concurrente) respecto de la del hilo principal del proceso.
  • Proceso multihilo: un hilo del proceso puede crear otro. Todos los hilos del proceso comparten un único espacio de memoria. Se usan técnicas de programación concurrente, utilizando servicios ofrecidos por una biblioteca o por el sistema operativo.
  • Biblioteca multihilo: conjunto de servicios para programación multihilo, sin que el sistema operativo se entere. La biblioteca multiplexa el “único hilo” que el sistema operativo ofrece por proceso. Si se bloquea un hilo se está bloqueando el “único hilo” del proceso.
  • Sistema multihilo: el sistema ofrece el conjunto de servicios para la programación multihilo. El sistema operativo gestiona que un proceso tenga más de un hilo. Todos los hilos del proceso comparten un único espacio de memoria. Si un hilo se bloquea, los demás hilos del proceso no se ven afectados.

Un proceso multihilo, sobre un sistema multihilo, sobre un multiprocesador, podría estar ejecutando simultáneamente en paralelo en más de una CPU, esto es, obteniendo tasas de utilización de CPU de más del 100%.

Este mismo proceso multihilo (usando una biblioteca multihilo), sobre un sistema monohilo, ejecutaría como máximo al 100% de CPU, aunque el sistema sea multiprocesador.

Para que la realización de esta primera tanda de preguntas ofrezca resultados interesantes, se recomienda encarecidamente que las realice en la máquina “triqui.fi.upm.es”.

Se pide que se introduzca usted en un sistema UNIX donde tenga cuenta abierta.


Un sistema UNIX es multiproceso y multiusuario.




Analicemos ahora el tipo de sistema con el que está trabajando. El directorio /proc, como ya habíamos visto anteriormente, recoge información sobre el sistema. Entre esta información se encuentra las características del procesador, en concreto, en el fichero cpuinfo.

  • processor.- nos indica el número de procesadores “virtuales” que contiene la máquina.
  • physical id.- nos proporciona el identificador físico de cada uno de los procesadores que contiene la máquina. Como es de esperar, si varios procesadores tienen el mismo physical id, es porque se trata del mismo procesador físico.
  • cpu cores.- nos permite conocer el número de núcleos que existen por procesador físico. Un valor de '1' indicará, por tanto, que el procesador contiene un único núcleo. Si el numero de procesadores virtuales es mayor que el número de procesadores físicos múltiplicado por el número de núcleos que tiene cada procesador, entonces la máquina utiliza hyper-threading. La tecnología de hyper-threading estará soportada si el flag ht está presente en el campo flags y si se utiliza kernel SMP.

Dada la información contenida en /proc/cpuinfo , conteste a las siguientes preguntas:



Además de la información proporcionada por /proc/cpuinfo, proporcionamos dos programas CPUs_pth y CPUs_prc, que nos van a permitir conocer (en cierto modo) la capacidad de computo del sistema (entendida como número total de incrementos de una variable de 64 bits) que pueden conseguir el número de procesos (o hilos) indicado en el número de segundos establecidos. Como se puede imaginar, este no es un método fiable, puesto que depende de la carga (de procesos) a la que esté sometida la máquina. Si en el sistema hay otros procesos que usan intensivamente la CPU es fácil que las medidas que usted obtenga sean muy dispares.

Analice el código del programa CPUs_prc. Comprobará que se crean tantos procesos (mediante fork) como se indique en el primer argumento, y que cada uno de estos procesos estará en ejecución durante un tiempo determinado por el segundo argumento.


Compile y ejecute el programa, por ejemplo, con los argumentos 1 10:

alumno@maquinaLinux~/PracticasAnalisis/ModuloSinCom$ ./CPUs_prc 1 10
Total work done by 1 process in 10 seconds is = 498176612

Además podemos utilizar el programa Times_C.c que nos proporciona los tiempos de ejecución de un proceso. Distinguimos entre tiempos “real”, “user” y “sys” (ver man 7 time). El tiempo “real” es el transcurrido desde el inicio de la ejecución hasta la terminación del proceso. Los tiempos “user” y “sys” son tiempos de procesador que ha utilizado el proceso. “user” es el tiempo de procesador ejecutando en modo usuario (sin privilegios de sistema). “sys” es el tiempo de procesador ejecutando en modo sistema en nombre del proceso, es decir, ejecutando los servicios invocados por el proceso. Si nuestro proceso es multihilo (como es el caso de CPUs_prc.c ), y nuestro sistema es multiprocesador, podrá suceder que cada uno de los hilos de ejecución se asignen a procesadores diferentes por lo que el tiempo “user” de procesador será superior al tiempo “real”.

alumno@maquinaLinux~/PracticasAnalisis/ModuloSinCom$ ./Times_C ./CPUs_prc 1 10
Total work done by 1 process in 10 seconds is = 4982684141
Times_C: »»» Real:10.000" User:10.000" Syst:0.000"

El resultado muestra como durante 10 segundos, 1 proceso en ejecución ha logrado realizar un total aproximado de 5000 millones de sumas. ¿Cuánto cómputo pueden realizar el doble de procesos en la mitad de tiempo? ¿El mismo o la mitad? Esto depende de si tenemos una única CPU o tenemos más (y obviamente de la carga del sistema).

alumno@maquinaLinux~/PracticasAnalisis/ModuloSinCom$ ./Times_C ./CPUs_prc 2 5
Total work done by 2 process in 5 seconds is = 4979025368
Times_C: »»» Real:5.010" User:10.000" Syst:0.000"

Resulta que efectivamente se alcanza una cantidad de cómputo prácticamente idéntica (del orden de los 5000 millones). De ello podríamos deducir que nuestra máquina es, al menos, un biprocesador. Además vemos como el tiempo “user” es el doble que el tiempo “real”, lo cual implica que cada proceso ha estado ejecutando en un procesador diferente.

Recuerde que estamos haciendo todo este tipo de pruebas sobre un sistema multiproceso y multiusuario, luego las medidas de tiempos que podamos hacer serán siempre aproximadas y prácticamente irrepetibles, al estar sometidas al indeterminismo del resto de la carga en el sistema.


El programa CPUs_pth.c presenta la misma funcionalidad que el programa CPUs_prc.c, pero utilizando procesos ligeros o threads. Siguiendo el mismo procedimiento que para CPUs_prc.c, podemos determinar si nuestro sistema es multihilo o si por el contrario el soporte para los threads es mediante una biblioteca multihilo.


Ciertos programas que ya se utilizaron en el capítulo de procesos nos permiten observar cómo sucede la concurrencia en o entre los procesos existentes en un sistema. Nos estamos refiriendo a:

Compart_*, Concurr_* y UnSegundo.c.



CONDICIÓN DE CARRERA

El acceso concurrente sin coordinación a recursos compartidos puede NO producir los resultados esperados.

En sistemas multiproceso, no es posible garantizar la velocidad relativa de los diferentes procesos en ejecución, es decir, no vamos a conocer a priori el orden en que se ejecutarán los procesos en nuestro sistema. Este hecho provoca que un acceso no coordinado a los recursos conpartidos por los procesos pueda producir resultados diferentes a los esperados. Este fenómeno se conoce como condición de carrera.

Se ha desarrollado el programa Carreras.c que pretende demostrar la existencia de condiciones de carrera, cuando no existe coordinación en el acceso a un recurso compartido por varios procesos.

Analice el código del programa Carreras.c

C-01.- void shared_free(void * ptr, unsigned size)
C-02.- {
C-03.-    munmap(ptr, size);
C-04.- }
C-05.- 
C-06.- void * shared_alloc(unsigned size)
C-07.- {
C-08.-    void * ptr = NULL;
C-09.-    int fd = open("/dev/zero", O_RDWR);
C-10.-    if (fd < 0) return NULL;
C-11.-    ptr = mmap(0, size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
C-12.-    close(fd);
C-13.-    return ptr;
C-14.- }
C-15.- 
C-16.- 
C-17.- 
C-18.- int main(void)
C-19.- {
C-20.-    int i, v;
C-21.-    volatile int * Variable = shared_alloc(sizeof(int));
C-22.-    if(Variable == NULL) return 1;
C-23.-    for (i = 0; i < 50; i++)
C-24.-    {
C-25.-       Variable[0] = 0;
C-26.-       switch(fork())
C-27.-       {
C-28.-          case -1:
C-29.-                  perror(MYNAME": fork()"); exit(1);
C-30.-          case 0:
C-31.-                  for (v = 0; v < 2500000; v++) Variable[0]++; exit(0);
C-32.-          default:
C-33.-                  for (v = 0; v < 2500000; v++) Variable[0]--; wait(NULL);
C-34.-       }
C-35.-       printf("\t%10d\n ", Variable[0]);
C-36.-    }
C-37.- 
C-38.-    shared_free((void*)Variable, sizeof(int));
C-49.-    return 0;
C-40.- }








COORDINACIÓN IMPLICITA VS. COORDINACIÓN EXPLICITA

Para evitar las condiciones de carrera, es necesario coordinar los accesos al recurso compartido.

Coordinación implícita: es aquella que realiza el Sistema Operativo para garantizar que no suceden condiciones de carrera entre procesos aparentemente independientes, pero que en realidad están compartiendo recursos del sistema. Por ejemplo, en la coutilización de ficheros los procesos comparten la posición sobre el archivo mediante descriptores de fichero duplicados. Aunque en ningún momento se utilice de manera explicita ningún mecanismo que coordine el acceso al recurso compartido, el sistema operativo se encarga de garantizar que mientras un proceso esté accediendo al fichero, ninguno más pueda modificarlo.

Coordinación explícita: es aquella que realiza explícitamente el programador, utilizando los mecanismos de sincronización adecuados, proporcionados por el lenguaje o por el Sistema Operativo, para conseguir que no sucedan condiciones de carrera entre procesos concurrentes que está programando y que están compartiendo recursos.

En clase se ven ejemplos de la utilización de diversos mecanismos de sincronización para la implementación de determinados modelos “clásicos” de programación concurrente.


MODELO PRODUCTOR CONSUMIDOR

Este modelo de interacción entre dos procesos concurrentes resuelve el problema de cómo comunicar (ordenadamente) información de uno a otro (en un sentido), cuando lo único que los dos procesos tienen en común es un espacio de almacenamiento de tamaño fijo limitado.

Utilizaremos en este apartado, el programa PC_PLs_mc.c, el cual constituye un ejemplo del modelo productor|consumidor utilizando procesos ligeros.

PC-01.- #define BUFF_SIZE      1024
PC-02.- #define TOTAL_DATOS  100000
PC-03.- 
PC-04.- int n_datos;                            
PC-05.- int buffer[BUFF_SIZE];                  
PC-06.- pthread_mutex_t mutex;                  
PC-07.- pthread_cond_t no_lleno, no_vacio;      
PC-08.- 
PC-09.- void Productor(void)
PC-10.- {
PC-11.-    int i, dato;
PC-12.- 
PC-13.-    for (i = 0; i < TOTAL_DATOS; i++) 
PC-14.-    {
PC-15.-       /*Producir el dato*/
PC-16.-       dato = i;
PC-17.-       pthread_mutex_lock(&mutex);
PC-18.-       while (n_datos == BUFF_SIZE)
PC-19.-          pthread_cond_wait(&no_lleno, &mutex);
PC-20.-       buffer[i % BUFF_SIZE] = dato;
PC-21.-       n_datos++;
PC-22.-       
PC-23.-       pthread_cond_signal(&no_vacio);
PC-24.-       pthread_mutex_unlock(&mutex);
PC-25.-    }
PC-26.- }
PC-27.- 
PC-28.- void Consumidor(void)
PC-29.- {
PC-30.-    int i, dato;
PC-31.- 
PC-32.-    for (i = 0; i < TOTAL_DATOS; i++) 
PC-33.-    {
PC-34.-       pthread_mutex_lock(&mutex);
PC-35.-       while (n_datos == 0)
PC-36.-          pthread_cond_wait(&no_vacio, &mutex);
PC-37.-       dato = buffer[i % BUFF_SIZE];
PC-38.-       n_datos--;
PC-39.-       pthread_cond_signal(&no_lleno);
PC-40.-       pthread_mutex_unlock(&mutex);
PC-41.- 
PC-42.-       /*Consumir el dato*/
PC-43.-       printf("\r %d   \r", dato);
PC-44.-       fflush(stdout);
PC-45.-    }
PC-46.-    printf("\n");
PC-47.-    fflush(stdout);
PC-48.- }
PC-49.- 
PC-50.- int main(void)
PC-51.- {
PC-52.-    pthread_t th1, th2;
PC-53.- 
PC-54.-    pthread_mutex_init(&mutex, NULL);                        /* Situación inicial */
PC-55.-    pthread_cond_init(&no_lleno, NULL);
PC-56.-    pthread_cond_init(&no_vacio, NULL);
PC-57.-    pthread_create(&th1, NULL, (void*)Productor, NULL);      /* Arranque */
PC-58.-    pthread_create(&th2, NULL, (void*)Consumidor, NULL);
PC-59.-    pthread_join(th1, NULL);                                 /* Esperar terminación */
PC-60.-    pthread_join(th2, NULL);
PC-61.-    pthread_mutex_destroy(&mutex);                           /* Destruir */
PC-62.-    pthread_cond_destroy(&no_lleno);
PC-63.-    pthread_cond_destroy(&no_vacio);
PC-64.- 
PC-65.-    return 0;
PC-66.- }




Compile (tenga en cuenta que utiliza procesos ligeros) y ejecute el programa:


MODELO LECTORES ESCRITORES

Este modelo de interacción entre procesos concurrentes resuelve el problema de ordenar los accesos a un repositorio común de información, de manera que se garantice una visión coherente de dicha información. Se debe permitir que varios lectores puedan acceder simultáneamente al recurso, pero al mismo tiempo se debe garantizar que cada escritor acceda en exclusiva, es decir, mientras un proceso escritor accede al recurso ningún otro proceso (ya sea lector o escritor) deberá acceder al mismo.

Para mostrar el funcionamiento de este modelo, se plantea la utilización de dos programas: Lector.c y Escritor.c. El primer realiza lecturas sobre un fichero compartido, que se ha definido de manera estática como BD, mientras que el proceso escritor, realiza lecturas sobre dicho fichero compartido.

A continuación se muestra el código del programa Escritor.c

E-01.- #define MYNAME  "Escritor"
E-02.- #include <fcntl.h>
E-03.- #include <stdio.h>
E-04.- #include <stdlib.h>
E-05.- #include <unistd.h>
E-06.- 
E-07.- int main(void)
E-08.- {
E-09.-    int fd, val=0, cnt;
E-10.-    struct flock fl;
E-11.- 
E-12.-    fl.l_whence = SEEK_SET;
E-13.-    fl.l_start = 0;
E-14.-    fl.l_len = 0;
E-15.-    fl.l_pid = getpid();
E-16.-    fd = open("BD", O_RDWR);
E-17.-    for (cnt = 0; cnt < 10; cnt++)
E-18.-    {
E-19.-       fl.l_type = F_WRLCK;
E-20.-       fcntl(fd, F_SETLKW, &fl);
E-21.-       lseek(fd, 0, SEEK_SET);
E-22.-       read(fd, &val, sizeof(int));
E-23.-       val++;
E-24.-       lseek(fd, 0, SEEK_SET);
E-25.-       write(fd, &val, sizeof(int));
E-26.-       fl.l_type = F_UNLCK;
E-27.-       fcntl(fd, F_SETLK, &fl);
E-28.-    }
E-29.-    return 0;
E-30.- }



Los programas Escritor.c y Lector.c están pensados para ser ejecutados de manera simultanea. En principio, podrán existir simultaneamente tantos procesos escritores y lectores como queramos.

Ejecute la siguiente secuencia. Primero creamos el archivo BD (que estará vacio) y a continuación lanzamos la ejecución simultanea de 3 procesos lectores y dos procesos escritores.

alumno@maquinaLinux~/PracticasAnalisis/ModuloSinCom$ > BD
alumno@maquinaLinux~/PracticasAnalisis/ModuloSinCom$ ./Lector & ./Escritor & ./Lector & ./Escritor & ./Lector
...



MODELO CLIENTE SERVIDOR

Este modelo de interacción entre procesos concurrentes resuelve el problema de acceder a un recurso gestionado por un proceso gestor (servidor), local o remoto. En el modelo cliente-servidor, este último es el encargado de proporcionar acceso a un servicio y por tanto de gestionar el acceso al/los recursos. El cliente accederá al servicio proporcionado por el servidor siguiendo un protocolo de petición-respuesta.

Para comprobar el funcionamiento del modelo cliente-servidor, se han diseñado dos programas: TCP_s.c y TCP_c.c que se corresponden con la aplicación servidor y cliente respectivamente.

A continuación se muestra el código de la aplicación TCP_s.c

TS-01.- #define MYNAME  "TCP_s"
TS-02.- #include <arpa/inet.h>                  
TS-03.- #include <netinet/in.h>                 
TS-04.- #include <netinet/tcp.h>                
TS-05.- #include <sys/socket.h>                 
TS-06.- #include <sys/types.h>                  
TS-07.- #include <sys/un.h>                     
TS-08.- #include <sys/wait.h>                   
TS-09.- #include <netdb.h>                      
TS-10.- #include <ctype.h>
TS-11.- #include <signal.h>
TS-12.- #include <stdio.h>
TS-13.- #include <stdlib.h>
TS-14.- #include <unistd.h>
TS-15.- 
TS-16.- void Timeout_Control(int signo)
TS-17.- {
TS-18.-    int timeout;
TS-19.-    char * text = "TIMEOUT!...Terminating now.\n";
TS-20.- 
TS-21.-    if (!signo)
TS-22.-    {
TS-23.-       text = getenv("TIMEOUT");
TS-24.-       if (text)
TS-25.-       {
TS-26.-          signal(SIGALRM, Timeout_Control);
TS-27.-          timeout = atoi(text);
TS-28.-          if (timeout >= 0)     alarm(timeout);
TS-29.-       }
TS-30.-    }
TS-31.-    else
TS-32.-    {
TS-33.-       write(2, text, strlen(text));    exit(0);
TS-34.-    }
TS-35.- }
TS-36.- 
TS-37.- void SIGCHLD_Handler(int signo)
TS-38.- {
TS-39.-    signal(SIGCHLD, SIGCHLD_Handler);
TS-40.-    if (signo == SIGCHLD)     waitpid(-1, NULL, WNOHANG);
TS-41.- }
TS-42.- 
TS-43.- int main(int argc, char * argv[])
TS-44.- {
TS-45.-    int sd, cd, size, ret;
TS-46.-    char ch;
TS-47.-    short int port;
TS-48.-    struct sockaddr_in s_ain, c_ain;
TS-49.- 
TS-50.-    Timeout_Control(0);
TS-51.-    SIGCHLD_Handler(0);
TS-52.- 
TS-53.-    sd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
TS-54.-    if (sd == -1)     perror(argv[0]);
TS-55.- 
TS-56.-    if (argc > 1)     port = atoi(argv[1]);
TS-57.-    else              port = 7777;
TS-58.- 
TS-59.-    bzero((char *) &s_ain, sizeof(s_ain));
TS-60.-    s_ain.sin_family = AF_INET;
TS-61.-    s_ain.sin_addr.s_addr = INADDR_ANY;
TS-62.-    s_ain.sin_port = htons(port);   /* 7 == echo port */
TS-63.- 
TS-64.-    ret = bind(sd, (struct sockaddr *) &s_ain, sizeof(s_ain));
TS-65.-     
TS-66.-    if (ret == -1)    perror(argv[0]);
TS-67.- 
TS-68.-    listen(sd, 5);
TS-69.-    while (1) 
TS-70.-    {
TS-71.-       size = sizeof(c_ain);
TS-72.-       cd = accept(sd, (struct sockaddr *) &c_ain, &size);
TS-73.-       switch (fork()) 
TS-74.-       {
TS-75.-          case -1:
TS-76.-                    perror("echo server");
TS-77.-                    return 1;
TS-78.-          case 0:
TS-79.-                    close(sd);
TS-80.-                    while (recv(cd, &ch, 1, 0) == 1) 
TS-81.-                    {
TS-82.-                       ch = toupper(ch);
TS-83.-                       send(cd, &ch, 1, 0);
TS-84.-                    }
TS-85.-                    close(cd);
TS-86.-                    return 0;
TS-87.-          default:
TS-88.-                    close(cd);
TS-89.-       } /* switch */
TS-90.-    } /* while */
TS-91.- } /* main */




Compile el programa TCP_s.c y ejecutelo en segundo plano (background).

alumno@maquinaLinux:~/PracticasAnalisis/ModuloSinCom$ ./TCP_s 18231 &
[1234]

En este ejemplo se utiliza el argumento 18231 para lanzar el proceso servidor, pero puede utilizar otros valores.


Utilizaremos el programa TCP_c.c como proceso cliente. Este programa puede recibir dos parámetros, uno o ninguno.


Realice un par de conexiones interactivas con su servidor, desde la máquina local. Y compruebe el funcionamiento del modelo cliente-servidor.

alumno@maquinaLinux:~/PracticasAnalisis/ModuloSinCom$ ./TCP_c 127.0.0.1 18231
Hola, ¿qué tal?
^D

Si se está trabajando en la máquina triqui.fi.upm.es, a través de varios terminales putty, asegúrese que en ambos terminales están conectado al mismo nodo (triqui3 o triqui4).

Recuerde que hemos arrancado el programa servidor como un demonio, esto es, en segundo plano y a la escucha en un canal de comunicación con dirección conocida. Para evitar que se nos quede este proceso latente en el sistema (consumiendo el puerto al que está asociado) deberemos matarlo.

Ejecute el mandato fg, para traerlo a primer plano y luego ^C para matarlo.

alumno@maquinaLinux:~/PracticasAnalisis/ModuloSinCom$ fg
./TCP_s 18231
^C
[1234] Interrupted

O bien, consulte su PID con un ps y luego láncele una señal con el mandato kill.

alumno@maquinaLinux:~/PracticasAnalisis/ModuloSinCom$ kill -9 1234
[1234] Killed

Intentemos ahora medir las prestaciones de este tipo de comunicación local.

Cree y tenga a mano un fichero de 1 Mega byte (por ejemplo, puede utilizar el programa Robot_B que se utilizó en el módulo de ficheros). Veremos cuanto tiempo (aproximado) tarda en trasferirse en ida y vuelta este fichero. Para medir el tiempo utilizaremos el mandato Times_C.

alumno@maquinaLinux:~/PracticasAnalisis/ModuloSinCom$ ./Times_C ./TCP_c 127.0.0.1 18231 < 1MB.dat > /dev/null
Times_C: »»» Real:X.xxx" User:XX.xxx" Syst:XX.xxx"


Intentemos ahora medir las prestaciones de la comunicación remota. Busque una máquina remota donde pueda compilar y ejecutar el servidor TCP (digamos que se llama triqui.fi.upm.es). Láncelo en dicha máquina remota y desde la máquina local (que debe ser otra), desde la que está realizando estás prácticas, vuelva a contactar y a medir el tiempo de transferir un megabyte.

alumno@maquinaLinux:~/PracticasAnalisis/ModuloSinCom$ Times_C ./TCP_c triqui.fi.upm.es 18231 <1MB.dat >/dev/null
Times_C: »»» Real:X.xxx" User:XX.xxx" Syst:XX.xxx"


No olvide terminar los procesos servidores que haya arrancado. De otro modo no podrán arrancar otro en el mismo puerto.

 
docencia/asignaturas/sox/prv/practicas/analisis_so5/modulo_sc.txt · Última modificación: 2019/07/18 18:27 (editor externo)
 
Recent changes RSS feed Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki