Laboratorio 4

Sincronización de procesos en JBACI

Un poco de historia

Hace unos 20 años Modechai (Moti) Ben-Ari desarrolló un simulador para la enseñanza de la programación concurrente. El simulador estuvo basado en el interprete Pascal-P de Niklaus Wirth que luego fue publicado en el libro de Ben-Ari Principios de Programación Concurrente (Prentice-Hall International, 1982). Después Ben-Ari hizo algunas modificaciones al simulador, en particular desarrolló un ambiente de entorno integrado, basado en la interface de usuario que tenía Turbo Pascal. Es fácil comprender que en la actualidad su mantenimiento es casi nulo y la interface de caracter no es agradable para el estudiante.

Con el devenir de los años otros educadores han desarrollado simuladores concurrentes de su propiedad. El más completo y ampliamente usado es BACI. Este simulador a diferencia del que creo Ben-Ari está basado en un subconjunto de C. Curiosamente el nombre está dedicado al que posiblemente los inspiró: Ben-Ari Concurrency Interpreter (BACI) cuyos autores son: Bill Bynum y Tracy Camp. Existen muchas versiones de BACI para distintos sistemas, una interface gráfica de usuario existe solo para sistemas Unix. Sin embargo, recientemente, hace algunos años David Strite desarrollo un nuevo interprete para el código virtual de BACI incluyendo un GUI. El interprete se llama jBACI  está escrito en JAVA y es portable a todas las plataformas.

jBACI es una integración del compilador original de BACI y el interprete de Strite en una IDE que contiene un editor, junto con extensiones para la GUI que simplifican su uso para novatos. Adicionalmente Ben-Ari ha modificado el compilador y el interprete para incluir comandos para dibujo graficos en un lienzo; esto posibilita a los estudiantes escribir programas concurrentes que son más divertidos que los programas basados en caracteres.

Archivos a necesarios

jBACI interpreta tanto el pascal concurrente como el subconjunto de C/C++. La interface reconoce el archivo por la extensión .pm para archivos de Pascal y .cm para los archivos de C.

En el siguiente archivo comprimido jbaci1-4-5Linux.zip se encuentra, en su versión para Linux1, el compilador para Pascal y C concurrente: bapas  y bacc respectivamente; un archivo de configuración, que tendrá que modificar de acuerdo a su necesidades; un directorio conteniendo abundantes ejemplos en Pascal y C; y el archivo en java: jbaci.jar. 

1 la versión para Linux fue portada por Andrés Barrios a partir de los fuentes del compilador y de la versión para MSWindows

Requisitos

     - Cualquier distribución de Linux: Ubuntu, Debian, etc.

     - Tener instalado Sun Java 5.0 o superior.

     -  Tener acceso a la cuenta del superusuario.

Procedimiento

1.- En un directorio temporal desempaquete el archivo zip

2.- Como superusuario copie los archivos bapas y bacc al directorio /usr/bin, otórgueles derechos de ejcución con la orden chmod.

3.- Cree un directorio con nombre ProgramasJBACI debajo de su directorio home, por ejemplo /home/alulab/ProgramasJBACI y copie en él, los archivos ejemplos que venian en el zip.

4.- Modifique el archivo config.cfg de la siguiente forma:

#jBACI configuration file
#Mon Mar 08 07:08:24 GMT 2004
SHOW_HISTORY_SOURCE=true
SUBWINDOW_Y=300
SUBWINDOW_X=300
INITIAL_CONSOLE=true
INITIAL_LINDA=true
G_YPOS=100
SOURCE_DIRECTORY=/home/alulab/ProgramasJBACI
G_WIDTH=600
GLOBALS_Y=350
GLOBALS_X=300
PASCAL_COMPILER=/usr/bin/bapas
SHOW_ACTIVE_DEFAULT=true
OPEN_MAIN_BY_DEFAULT=true
FRAME_Y=600
PTAB_Y=300
FRAME_X=800
G_HEIGHT=450
CONSOLE_Y=350
PTAB_X=150
CONSOLE_X=0
C_COMPILER=/usr/bin/bacc
STOP_ON_SWAP_DEFAULT=false
SOURCE_FONT_SIZE=14
TUPLE_SPACE=5
PCODE_FONT_SIZE=12
HISTORY_Y=350
HISTORY_X=600
INPUT_Y=0
INPUT_X=0
INITIAL_GLOBALS=true
G_XPOS=200
PROCESS_Y=350
PROCESS_X=300
INITIAL_HISTORY=false
TABLE_FONT_SIZE=12
WRITE_HISTORY_FILE=false
LINDA_Y=350
LINDA_X=600

Usted deberá modificar lo que está en negrita.

5.- Abra una terminal y ubíquese en el directorio donde se encuentra el archivo jbaci.jar y ejecute la siguiente línea:

    $java -jar  jbaci.jar   

El siguiente archivo jbaci1-4-5docs.zip contiene la guia del usuario del compilador BACI. Es necesario que los lea para saber con qué instrucciones puede contar para programar en C.

También puede serles util los siguientes enlaces: 

      http://www.mines.edu/fs_home/tcamp/baci/

       http://stwww.weizmann.ac.il/g-cs/benari/jbaci/

Sincronizando procesos

Abajo se muestra un programa sencillo donde se han dibujado dos rectangulos y estos avanzan de forma paralela, el código y la salida a continuación:

// Demonstate jBACI graphics; without barrier program.
#include "gdefs.cm"
const
    int SQUARE1 = 1;    int SQUARE2 = 2;       
    int BARRER = 3;     int DELTA = 11;   
int Xfinal = 600;

    void MoveS1() {
        int i=0,r;
        while (i <= Xfinal) {
            r = random(DELTA);
            i = i + r;
            moveby(SQUARE1, r, 0);
        }
    }

    void MoveS2() {
        int i=0,r;
        while (i <= Xfinal) {
            r = random(DELTA);
            i = i + r;
            moveby(SQUARE2, r, 0);           
        }
    }

void main() {
    create(SQUARE1, RECTANGLE, RED,   30, 50,  30, 30);
    create(SQUARE2, RECTANGLE, BLUE,  30, 100, 30, 30);
        create(BARRER, LINE, BLACK, 350,10,350,400);
    cobegin {
        MoveS2();MoveS1();
    }
}

Observe que en este programa existe una línea que simula una barrera, pero que sin embargo ambos rectángulos la atrviesan sin ningún problema.

Ahora se mostrará un programa donde el primer rectángulo que llegue a la barrera esperará al otro

// Demonstate jBACI graphics; one barrier.
#include "gdefs.cm"
const
    int SQUARE1 = 1;    int SQUARE2 = 2;       
    int BARRIER = 3;    int DELTA = 11;       
    int Xbarrier = 350; int Xfinal = 600;

    binarysem s12=0, s21=0;

    void MoveS1() {
        int i=30,sw=0,r;
        while (i <= Xfinal) {
            r = random(DELTA);
            i = i + r;
            if((sw == 0) && (i >= Xbarrier)) {
               sw=1;
               moveto(SQUARE1, 350, 50);           
               signal(s12);
               wait(s21);           
            } else moveby(SQUARE1, r, 0);
        }
    }

    void MoveS2() {
        int i=30,sw=0,r;
        while (i <= Xfinal) {
            r = random(DELTA);
            i = i + r;
            if((sw == 0) && (i >= Xbarrier)) {
               sw=1;
               moveto(SQUARE2, 350, 100);                  
               signal(s21);
               wait(s12);           
            } else moveby(SQUARE2, r, 0);           
        }
    }

void main() {
    create(SQUARE1, RECTANGLE, RED,   30, 50,  30, 30);
    create(SQUARE2, RECTANGLE, BLUE,  30, 100, 30, 30);
    create(BARRIER, LINE, BLACK, 350,10,350,400);
    if(random(2))
        cobegin {
           MoveS2();MoveS1();
         
    } else  cobegin {
           MoveS1();MoveS2();
    }    
}

El siguiente programa tiene dos barreras. En la primera barrera se sincroniza el primero con el tercero, es decir el primero que llega espera al otro. En la segunda barrera se sincroniza el primero con el segundo. a continuación el código:

// Demonstate jBACI graphics; two barrier.
#include "gdefs.cm"
const
    int SQUARE1 = 1;    int SQUARE2 = 2;     int SQUARE3 = 3; 
    int BARRIER1 = 4;    int BARRIER2 = 5;    int DELTA = 11;
    int Xbarrier1 = 200;    int Xbarrier2 = 400; int Xfinal = 600;

    binarysem s[2][2];

    void MoveS1() {
        int i=30,sw=0,r;
        while (i <= Xfinal) {
            r = random(DELTA);
            i = i + r;
            if((sw == 0) && (i >= Xbarrier1) && (i < Xbarrier2)) {
               sw=1;
               moveto(SQUARE1, 200, 50);
               signal(s[0][1]);
               wait(s[1][0]);           
            } else    if((sw == 1) && (i >= Xbarrier2)) {
               sw=0;
               moveto(SQUARE1, 400, 50);
               signal(s[0][0]);
               wait(s[1][1]);           
              } else moveby(SQUARE1, r, 0);
        }
    }

    void MoveS2() {
        int i=30,sw=0,r;
        while (i <= Xfinal) {
            r = random(DELTA);
            i = i + r;
            if((sw == 0) && (i >= Xbarrier2)) {
               sw=1;
               moveto(SQUARE2, 400, 100);
               signal(s[1][1]);
               wait(s[0][0]);           
            }  else moveby(SQUARE2, r, 0);           
        }
    }

    void MoveS3() {
        int i=30,sw=0,r;
        while (i <= Xfinal) {
            r = random(DELTA);
            i = i + r;
            if((sw == 0) && (i >= Xbarrier1)) {
               sw=1;
               moveto(SQUARE3, 200, 150);
               signal(s[1][0]);
               wait(s[0][1]);           
            } else    moveby(SQUARE3, r, 0);           
        }
    }


void main() {
    create(SQUARE1, RECTANGLE, RED,   30, 50,  30, 30);
    create(SQUARE2, RECTANGLE, BLUE,  30, 100, 30, 30);
    create(SQUARE3, RECTANGLE, GREEN,  30, 150, 30, 30);   

        create(BARRIER1, LINE, BLACK, 200,10,200,400);
    create(BARRIER2, LINE, BLACK, 400,10,400,400);
    cobegin {
        MoveS1();MoveS2();MoveS3();
    }
}

Nota

Existe una versión de jBACI para MS-Windows, puede obtenerla de este enlace jbaci1-4-5MSWindows.zip. Sin embargo debe tener en cuenta que el laboratorio se llevará a cabo sobre Linux Ubuntu.

TAREA

1.- Actualmente los rectángulos se detienen en las barreras por el lado izquierdo, modifique los programas para que se detengan por el lado derecho (es decir antes de atravezar la barrera).

2.- Modifique el programa con una sola barrera, para que en lugar de que sea dos funciones MoveS1() y MoveS2(): sea una sola función con un argumento que permita hacer la distinción.

3.- En base a los programas mostrados elabore uno que muestre 3 barreras. En la primera barrera se sincronizan el primero y el segundo rectángulo. En la segunda barrera se sincroniza el segundo y el tercero y en la última barrera se sincroniza el primer y tercer rectángulo.

4.- Elabore un programa que tenga dos barreras una vertical y otra horizontal. Un ractángulo recorre sobre el eje X y el otro recorre sobre el eje Y, el primero que llegue a su barrera puede pasar sin detenerse, pero el que llega segundo debe detenerse de manera que se evite la colisión. Ambos rectangulos deben estar a distancias iguales en sus respectivos ejes.