COMP309/509 - Parallel and Distributed Computing

Lecture 4 - Interprocess Communication

By Mitchell Welch

University of New England


Reading


Summary


File I/O Revision

#include  <fcntl.h>

// read(...) returns the number of bytes read or -1 on error
// errno is also set upon on error
int  read(  int  handle,  void  *buffer,  size_t  nbyte );

// write returns the number of bytes written or -1 on error
//errno is also set upon error
int  write(  int  handle,  void  *buffer,  size_t  nbyte  );

File I/O Revision


File I/O Revision

// The contents of the string pointed to by str are appended to the 
// beginning of the errno message
void perror ( const char * str );
#include <stdio.h>

int main ()
{
  FILE * pFile;
  pFile=fopen ("unexist.ent","rb");
  if (pFile==NULL)
    perror ("The following error occurred");
  else
    fclose (pFile);
  return 0;
}

File I/O Revision

int i, buffsize, bytes;
char buff[buffsize];
...
for(i = 0; i < buffsize; i++){
    bytes = read(STDIN_FILENO, &buff[i], sizeof(char));
    ...
}

File I/O Revision

//Example 1
int integer, bytes;
...
bytes = read(STDIN_FILENO, &integer, sizeof(int));

Example 2
typedef struct token_header {
  ....
} token_hdr_t;  
token_hdr_t thp;
bytes =  read(fd,&thp,sizeof(token_hdr_t));

File I/O Revision


File I/O Revision


Interprocess Communication with Buffers


#include <unistd.h>
int pipe(int filedes[2]);

Interprocess Communication with Buffers

.center[center-aligned image]


Interprocess Communication with Buffers


Interprocess Communication with Buffers


Interprocess Communication with Buffers

.center[center-aligned image]


Interprocess Communication with Buffers


Interprocess Communication with Buffers

int main(void) {
    int     n;
    int     fd[2];
    pid_t   pid;
    char    line[MAXLINE];

    if (pipe(fd) < 0)
        perror("pipe error");
    if ((pid = fork()) < 0) {
        perror("fork error");
    } else if (pid > 0) {       /* parent */
        close(fd[0]);
        write(fd[1], "hello world\n", 12);
    } else {                    /* child */
        close(fd[1]);
        n = read(fd[0], line, MAXLINE);
        write(STDOUT_FILENO, line, n);
    }
    exit(0);
}

Interprocess Communication with Buffers

#include <unistd.h>

int dup(int filedes)
int dup2(int filedes, int filedes2);

Interprocess Communication with Buffers


A Ring of Processes


Building a Ring-of-Processes for Computation


Building a Ring-of-Processes for Computation


Building a Ring-of-Processes for Computation

.center[center-aligned image]


Building a Ring-of-Processes for Computation

void make_trivial_ring(){
  int  fd[2];     
  pipe (fd);
  dup2(fd[0], STDIN_FILENO);
  dup2(fd[1], STDOUT_FILENO);
  close(fd[0]);
  close(fd[1]); 
}

Building a Ring-of-Processes for Computation

.center[center-aligned image]

Building a Ring-of-Processes for Computation


Building a Ring-of-Processes for Computation

void add_new_node(int *pid){
  int   fd[2];
  pipe (fd);
  *pid = fork();
  if (*pid > 0)  dup2(fd[1], STDOUT_FILENO);
  else           dup2(fd[0], STDIN_FILENO);
  close(fd[0]); 
  close(fd[1]); 
}

Building a Ring-of-Processes for Computation

.center[center-aligned image]


Building a Ring-of-Processes for Computation

.center[center-aligned image]


Building a Ring-of-Processes for Computation

.center[center-aligned image]


Building a Ring-of-Processes for Computation

.center[center-aligned image]


Building a Ring-of-Processes for Computation

.center[center-aligned image]


Building a Ring-of-Processes for Computation

int main(int argc,  char *argv[ ]){
  int  i, childpid;

  make_trivial_ring();
  for (i = 1; i < atoi(argv[1]); i++){
    add_new_node(&childpid);
    if (childpid) break;   }
   fprintf(stderr,
       "I'm %d ID = %d parent ID = %d\n",
           i, (int)getpid(), (int)getppid());
   sleep(5);
   exit(0); 
}

Note the way the ring grows, with the parent breaking out of the loop. We could just as easily do it the other way, but this way is more convenient.


Ring-of-Processes full Listing

/* written by ian a. mason @ une march '98 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
int parse_args(int argc,  char *argv[ ], int *np){
  if ( (argc != 2) || ((*np = atoi (argv[1])) <= 0) ) {
    fprintf (stderr, "Usage: %s nprocs\n", argv[0]);
    return(-1); };
  return(0); 
}
...

Ring-of-Processes full Listing

int make_trivial_ring(){   
  int   fd[2];
  if (pipe (fd) == -1) 
    return(-1); 
  if ((dup2(fd[0], STDIN_FILENO) == -1) ||
      (dup2(fd[1], STDOUT_FILENO) == -1)) 
    return(-2); 
  if ((close(fd[0]) == -1) || (close(fd[1]) == -1))   
    return(-3); 
  return(0); }

Ring-of-Processes full Listing

int add_new_node(int *pid){
  int fd[2];
  if (pipe(fd) == -1) 
    return(-1); 
  if ((*pid = fork()) == -1)
    return(-2); 
  if(*pid > 0 && dup2(fd[1], STDOUT_FILENO) < 0)
    return(-3); 
  if (*pid == 0 && dup2(fd[0], STDIN_FILENO) < 0)
    return(-4); 
  if ((close(fd[0]) == -1) || (close(fd[1]) == -1)) 
    return(-5);
  return(0);
}

Ring-of-Processes full Listing

int main(int argc,  char *argv[ ]){
   int   i;             /* number of this process (starting with 1)   */
   int   childpid;      /* indicates process should spawn another     */ 
   int   nprocs;        /* total number of processes in ring          */ 
   if(parse_args(argc,argv,&nprocs) < 0) exit(EXIT_FAILURE);
   if(make_trivial_ring() < 0){
     perror("Could not make trivial ring");
     exit(EXIT_FAILURE); };
   for (i = 1; i < nprocs;  i++) {
     if(add_new_node(&childpid) < 0){
       perror("Could not add new node to ring");
       exit(EXIT_FAILURE); };
     if (childpid) break; };
   /* ring process code  */

   fprintf(stderr, "node %d of %d\n", i, nprocs);
   exit(EXIT_SUCCESS);
}     /* end of main program here */

Summary


Reading


Next Lecture