Fork Join Example



next up previous contents index
Next: Dot Product Up: Program Examples Previous: Fork-Join

Fork Join Example

/* 
    Fork Join Example 
    Demonstrates how to spawn processes and exchange messages
*/

/* defines and prototypes for the PVM library */
#include <pvm3.h>

/* Maximum number of children this program will spawn */
#define MAXNCHILD   20
/* Tag to use for the joing message */
#define JOINTAG     11
int
main(int argc, char* argv[])
{

    /* number of tasks to spawn, use 3 as the default */
    int ntask = 3;
    /* return code from pvm calls */
    int info;
    /* my task id */
    int mytid;
    /* my parents task id */
    int myparent;
    /* children task id array */
    int child[MAXNCHILD];
    int i, mydata, buf, len, tag, tid;
    /* find out my task id number */
    mytid = pvm_mytid();

    /* check for error */
    if (mytid < 0) { 
        /* print out the error */
        pvm_perror(argv[0]); 
        /* exit the program */ 
        return -1;
        }
    /* find my parent's task id number */
    myparent = pvm_parent();

    /* exit if there is some error other than PvmNoParent */
    if ((myparent < 0) && (myparent != PvmNoParent)) {
        pvm_perror(argv[0]);
        pvm_exit();
        return -1;
        }
    /* if i don't have a parent then i am the parent */
    if (myparent == PvmNoParent) {
        /* find out how many tasks to spawn */
        if (argc == 2) ntask = atoi(argv[1]);
        /* make sure ntask is legal */
        if ((ntask < 1) || (ntask > MAXNCHILD)) { pvm_exit(); return 0; }

        /* spawn the child tasks */
        info = pvm_spawn(argv[0], (char**)0, PvmTaskDefault, (char*)0,
            ntask, child);
        /* print out the task ids */
        for (i = 0; i < ntask; i++) 
            if (child[i] < 0) /* print the error code in decimal*/
                printf(" %d", child[i]);
            else  /* print the task id in hex */
                printf("t%x\t", child[i]);
        putchar('\n');
        /* make sure spawn succeeded */
        if (info == 0) { pvm_exit(); return -1; }

        /* only expect responses from those spawned correctly */
        ntask = info;
    
        for (i = 0; i < ntask; i++) {
            /* recv a message from any child process */
            buf = pvm_recv(-1, JOINTAG);
            if (buf < 0) pvm_perror("calling recv");
            info = pvm_bufinfo(buf, &len, &tag, &tid);
            if (info < 0) pvm_perror("calling pvm_bufinfo");
            info = pvm_upkint(&mydata, 1, 1);
            if (info < 0) pvm_perror("calling pvm_upkint");
            if (mydata != tid) printf("This should not happen!\n");
            printf("Length %d, Tag %d, Tid t%x\n", len, tag, tid);
            }
        pvm_exit();
        return 0;
        }
   /* i'm a child */
   info = pvm_initsend(PvmDataDefault);
   if (info < 0) {
      pvm_perror("calling pvm_initsend"); pvm_exit(); return -1;
      }
   info = pvm_pkint(&mytid, 1, 1);
   if (info < 0) {
      pvm_perror("calling pvm_pkint"); pvm_exit(); return -1;
      }
   info = pvm_send(myparent, JOINTAG);
   if (info < 0) {
      pvm_perror("calling pvm_send"); pvm_exit(); return -1;
      }
   pvm_exit();
   return 0;
}

Figure gif shows the output of running forkjoin. Notice that the order the messages were received is nondeterministic. Since the main loop of the parent processes messages on a first-come first-serve basis, the order of the prints are simply determined by time it takes messages to travel from the child tasks to the parent .

 % forkjoin
 t10001c t40149  tc0037
 Length 4, Tag 11, Tid t40149
 Length 4, Tag 11, Tid tc0037
 Length 4, Tag 11, Tid t10001c
 % forkjoin 4
 t10001e t10001d t4014b  tc0038
 Length 4, Tag 11, Tid t4014b
 Length 4, Tag 11, Tid tc0038
 Length 4, Tag 11, Tid t10001d
 Length 4, Tag 11, Tid t10001e

Figure: Output of fork-join program