Parallel Programming in C for the Transputer
© D. Thiébaut, 1995



5-5 A Complete Program

We now look at the complete program implementing the Mandelbrot set. The program makes use of several new files that are included in the Tek[1 ] graphics package offered by Computer Systems Architects. The header filegraph.h contains the prototypes of the graphic functions. Most Borland's Turbo C graphic functions are supported by the Tek package, making the transfer of Turbo C graphics program written for a PC compatible to a transputer network almost instantaneous. The cio.exe driver which normally runs on the host is replaced by tgio.exe, which intercepts all the standard I/O functions along with the calls to the graphic functions. Finally the library t4graph (for T400 transputers) or t8graph (for T800 transputers) must be provided to the linker during the final linking process.

/* =======================================================================
   mandl_tf.c

   DESCRIPTION:

   Mandelbrot in C with floating point.
   Runs on as few as one transputer, and uses two concurrent tasks
   to display the mandelbrot set.  One task relays points generated by 
   nodes down the link which are sending them back to PC, as well as
   points generated by the second task.  The second tasks implement the
   mandelbrot set algorithm.
   The program interfaces with tgio.exe running on the PC host.

   Supports TurboC-type graphics function but relies on PC to
   execute them.

   TO COMPILE AND RUN:

   make -f mandl_tf
   chainnif -# 1 -1 mandl_tf  -nif mandl_tf.nif
   ld-net mandl_tf

   ASSOCIATED NIF-FILE

   buffer_size     200;
   host_server     tgio.exe;
   level_timeout   400;
   decode_timeout  2000;

   1, mandl_tf, R0, 0, , ,;

 ====================================================================== */
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "conc.h"
#include "graph.h"

/* =========================== DEFINITIONS ============================ */
#define SIZEINT   ((int) sizeof(int))
#define NO_NODES  1                            /* number of transputers */
                                               /* This macro can be set */
                                               /* between 1 and 5       */

/* =========================== PROTOTYPES ============================= */
void DoMandelbrot(void);
void Task1(Process *Task1P, Channel *softc);
void Task2(Process *Task2P, Channel *softc);

/* -------------------------------------------------------------------- */
/*                                 MAIN                                 */
/* -------------------------------------------------------------------- */
int main(void)
{
     if (_node_number==1)
     {
          /* request auto detection */
          int gdriver = DETECT, gmode, errorcode;
          char *msg;

          /* initialize graphics mode */
          initgraph(&gdriver, &gmode, "C:\\TC_V3\\BGI");

          /* read result of initialization */
          errorcode = graphresult();

          if (errorcode!=grOk)         /* an error occurred */
          {
               printf("Graphics error: ");
               grapherrormsg(errorcode, msg);
               printf("%s\n", msg);
               exit(1);                /* return with error code */
          }

          /* do mandelbrot set */
          DoMandelbrot();

          /* clean up */
          closegraph();
          exit();
     }
     else
          DoMandelbrot();

     exit();
}

/* -------------------------------------------------------------------- */
/* DOMANDELBROT                                                         */
/* Generates mandelbrot set in (-2,-1.5)-(1,1.5) rectangle of the       */
/* complex plane.                                                       */
/* -------------------------------------------------------------------- */
#define WS_SIZE 8192
void DoMandelbrot(void)
{
     Process *Task1P, *Task2P;
     Channel *softc;

     softc = ChanAlloc();
     Task1P = ProcAlloc(Task1, WS_SIZE, 1, softc);
     Task2P = ProcAlloc(Task2, WS_SIZE, 1, softc);
     if ((Task1P==NULL) || (Task2P==NULL) || (softc==NULL))
          return;

     ProcPar(Task1P, Task2P, 0);
     ChanFree(softc);
     ProcFree(Task1P);
     ProcFree(Task2P);
}

/* -------------------------------------------------------------------- */
/* TASK2                                                                */
/* Serves as a relay.                                                   */
/* -------------------------------------------------------------------- */
void Task2(Process *Task2P, Channel *softc)
{
     int Buffer[3] = {0,0,0};
     int Index;
     int NotDoneYet = (NO_NODES>1)? 2: 1;

     switch (_node_number)
     {
          case 1: while (NotDoneYet)
                  {
                       Index = ProcAlt(LINK1IN, softc, 0);
                       if (Index==1)
                            ChanIn(softc, (char *) Buffer, 3*SIZEINT);
                       else
                            ChanIn(LINK1IN, (char *) Buffer, 3*SIZEINT);

                       if (Buffer[0]==-1)
                            NotDoneYet--;
                       else
                            putpixel(Buffer[0], Buffer[1], Buffer[2]);
                  }
                  break;
          case 2:
          case 3:
          case 4: while (NotDoneYet)
                  {
                       Index = ProcAlt(LINK1IN, softc, 0);
                       if (Index==1)
                            ChanIn(softc, (char *) Buffer, 3*SIZEINT);
                       else
                            ChanIn(LINK1IN, (char *) Buffer, 3*SIZEINT);

                       if (Buffer[0]==-1)
                            NotDoneYet--;
                       else
                            ChanOut(LINK0OUT, (char *) Buffer, 3*SIZEINT);
                  }
                  Buffer[0] =-1;
                  ChanOut(LINK0OUT, (char *) Buffer, 3*SIZEINT);
                  break;
          case 5: do
                  {
                       ChanIn(softc, (char *) Buffer, 3*SIZEINT);
                       ChanOut(LINK0OUT, (char *) Buffer, 3*SIZEINT);
                  }
                  while (Buffer[0]!=-1);
     }
}

/* -------------------------------------------------------------------- */
/* TASK1                                                                */
/* Does the computation for each point                                  */
/* -------------------------------------------------------------------- */
void Task1(Process *Task1P, Channel *softc)
{
     float localXmin, localXmax, localYmin, localYmax;
     float DeltaX, DeltaY, Cx, Cy;
     int i, j, color;
     float xn, yn, xn_1, yn_1, distance, MaxDist;
     int maxcolor, maxx, maxy, StartOffset;
     int Buffer[3];

     if (_node_number==1)
     {
          maxcolor = getmaxcolor();
          maxx = getmaxx();
          maxy = getmaxy();
     }
     else
     {
          ChanIn(LINK0IN, (char *) &maxcolor, SIZEINT);
          ChanIn(LINK0IN, (char *) &maxx, SIZEINT);
          ChanIn(LINK0IN, (char *) &maxy, SIZEINT);
     }
     if (_node_number<NO_NODES)
     {
          ChanOut(LINK1OUT, (char *) &maxcolor, SIZEINT);
          ChanOut(LINK1OUT, (char *) &maxx, SIZEINT);
          ChanOut(LINK1OUT, (char *) &maxy, SIZEINT);
     }

     StartOffset = _node_number-1;

     /*--- define threshold for Zn series ---*/
     MaxDist = 100.0;

     /*--- define boundaries (-2,-1.5) lower-left, (1,1.5) upper right---*/
     localXmin =-2.0;
     localXmax = 1.0;
     localYmin =-1.5;
     localYmax =+1.5;

     /*--- define x and y increment for each pixel ---*/
     DeltaX = (localXmax-localXmin)/maxx;
     DeltaY = (localYmax-localYmin)/maxy;

     /*--- start the loop. ---*/
     Cx = localXmin+((_node_number-1) * DeltaX);
     DeltaX = (localXmax-localXmin)*NO_NODES/maxx;
     for (i = StartOffset; i<=maxx; i += NO_NODES)
     {
          Cy = localYmin;
          for (j = 0; j<=maxy; j++)
          {
               xn = 0;
               yn = 0;
               for (color = 0; color<maxcolor; color++)
               {
                    /*--- compute xn+1 = (xn*xn) - (yn*yn) + Cx ---*/
                    xn_1 = xn*xn-yn*yn+Cx;

                    /*--- compute yn+1 = 2*xn*yn + Cy ---*/
                    yn = 2*xn*yn+Cy;

                    /*--- update ---*/
                    xn = xn_1;

                    /*--- compute distance = xn*xn + yn*yn ---*/
                    distance = xn*xn+yn*yn;
                    if (distance>=MaxDist)
                         break;
               }

               /*--- we've exited the loop.  Found out color of point ---*/
               /*--- if color is black then don't "putpixel" it since ---*/
               /*--- the background is already black!                 ---*/
               if ((color<maxcolor) && (color!=BLACK))
               {
                    Buffer[2] = color;
                    Buffer[0] = i;
                    Buffer[1] = j;
                    ChanOut(softc, (char *) Buffer, 3*SIZEINT);
               }


               Cy += DeltaY;
          }
          Cx += DeltaX;
     }

     /*--- tell other task that we are done ---*/
     Buffer[0] =-1;
     ChanOut(softc, (char *) Buffer, 3*SIZEINT);
}

Listing 4: Listing of Mandelbrot set program. This program works in conjunction with tgio driver on the host. T8graph library contains graphics primitives to allow the root transputer to access the graphics screen.

[Previous] [HOME] [NEXT]