after pipe(fd) executes.

Team-FLY

7.2 Ring Formation

This section develops a ring of processes starting with a ring containing a single process. You should review Section 4.6 if you are not clear on file descriptors and redirection.

Example 7.1

The following code segment connects the standard output of a process to its standard input through a pipe. We omit the error checking for clarity.

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

Figures 7.2 “7.4 illustrate the status of the process at various stages in the execution of Example 7.1. The figures use [0] to designate standard input and [1] to designate standard output. Be sure to use STDIN_FILENO and STDOUT_FILENO when referring to these file descriptors in program code . The entries of the file descriptor table are pointers to entries in the system file table. For example, pipe write in entry [4] means "a pointer to the write entry in the system file table for pipe ," and standard input in entry [0] means "a pointer to the entry in the system file table corresponding to the default device for standard input" ”usually the keyboard.

Figure 7.2 depicts the file descriptor table after the pipe has been created. File descriptor entries [3] and [4] point to system file table entries that were created by the pipe call. The program can now write to the pipe by using a file descriptor value of 4 in a write call.

Figure 7.2. Status of the process of Example 7.1 after pipe(fd) executes.

graphics/07fig02.gif

Figure 7.3 shows the status of the file descriptor table after the execution of the dup2 functions. At this point the program can write to the pipe using either 1 or 4 as the file descriptor value. Figure 7.4 shows the configuration after descriptors [3] and [4] are closed.

Figure 7.3. Status of the process of Example 7.1 after both dup2 functions execute.

graphics/07fig03.gif

Figure 7.4. Status of the process at the end of Example 7.1.

graphics/07fig04.gif

Exercise 7.2

What happens if, after connecting standard output to standard input through a pipe, the process of Example 7.1 executes the following code segment?

 int i, myint; for (i = 0; i < 10; i++) {    write(STDOUT_FILENO, &i, sizeof(i));    read(STDIN_FILENO, &myint, sizeof(myint));    fprintf(stderr, "%d\n", myint); } 

Answer:

The code segment outputs the integers from 0 to 9 to the screen ( assuming that standard error displays on the screen).

Exercise 7.3

What happens if you replace the code in Exercise 7.2 by the following code?

 int i, myint; for (i = 0; i < 10; i++) {    read(STDIN_FILENO, &myint, sizeof(myint));    write(STDOUT_FILENO, &i, sizeof(i));    fprintf(stderr, "%d\n", myint); } 

Answer:

The program hangs on the first read because nothing had yet been written to the pipe.

Exercise 7.4

What happens if you replace the code in Exercise 7.2 by the following?

 int i, myint; for (i = 0; i < 10; i++) {    printf("%d ", i);    scanf("%d", &myint);    fprintf(stderr, "%d\n", myint); } 

Answer:

The program may hang on the scanf if the printf buffers its output. Put an fflush ( stdout ) after the printf to get output.

Example 7.5

The following code segment creates a ring of two processes. Again, we omit error checking for clarity.

 int fd[2]; pid_t haschild; pipe(fd);                                                         /* pipe a */ dup2(fd[0], STDIN_FILENO); dup2(fd[1], STDOUT_FILENO); close(fd[0]); close(fd[1]); pipe(fd);                                                         /* pipe b */ haschild = fork(); if (haschild > 0)    dup2(fd[1], STDOUT_FILENO);            /* parent(A) redirects std output */ else if (!haschild)    dup2(fd[0], STDIN_FILENO);               /* child(B) redirects std input */ close(fd[0]); close(fd[1]); 

The parent process in Example 7.5 redirects standard output to the second pipe. (It was coming from the first pipe.) The child redirects standard input to come from the second pipe instead of the first pipe. Figures 7.5 “7.8 illustrate the connection mechanism.

Figure 7.5. Connections to the parent process of Example 7.5 after the second pipe(fd) call executes.

graphics/07fig05.gif

Figure 7.5 shows the file descriptor table after the parent process A creates a second pipe. Figure 7.6 shows the situation after process A forks child process B. At this point, neither of the dup2 functions after the second pipe call has executed.

Figure 7.6. Connections of the processes of Example 7.5 after the fork . Process A is the parent and process B is the child.

graphics/07fig06.gif

Figure 7.7 shows the situation after the parent and child have each executed their last dup2 . Process A has redirected its standard output to write to pipe b, and process B has redirected its standard input to read from pipe b. Finally, Figure 7.8 shows the status of the file descriptors after all unneeded descriptors have been closed and a ring of two processes has been formed .

Figure 7.7. Connections of the processes of Example 7.5 after the if statement executes. Process A is the parent and process B is the child.

graphics/07fig07.gif

Figure 7.8. Connections of the processes of Example 7.5 after the entire code segment executes. Process A is the parent and process B is the child.

graphics/07fig08.gif

Exercise 7.6

What would happen if the code of Exercise 7.2 is inserted after the ring of two processes of Example 7.5?

Answer:

The new code is executed by two processes. Each process writes 10 integers to the pipe and reads the integers written by the other process. The processes cannot get too far out of step, since each process needs to read from the other before writing the next value. You should see two lines of 0 followed by two lines of 1, etc.

The code of Example 7.5 for forming a ring of two processes easily extends to rings of arbitrary size . Program 7.1 sets up a ring of n processes. The value of n is passed on the command line (and converted to the variable nprocs ). A total of n pipes is needed. Notice, however, that the program needs an array only of size 2 rather than 2 n to hold the file descriptors. After the ring of two processes is created, the parent drops out and the child forks again. (Try to write your own code before looking at the ring program.)

Program 7.1 ring.c

A program to create a ring of processes .

 #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> int main(int argc,  char *argv[ ]) {    pid_t childpid;             /* indicates process should spawn another     */    int error;                  /* return value from dup2 call                */    int fd[2];                  /* file descriptors returned by pipe          */    int i;                      /* number of this process (starting with 1)   */    int nprocs;                 /* total number of processes in ring          */            /* check command line for a valid number of processes to generate */    if ( (argc != 2)  ((nprocs = atoi (argv[1])) <= 0) ) {        fprintf (stderr, "Usage: %s nprocs\n", argv[0]);        return 1;    }    if (pipe (fd) == -1) {      /* connect std input to std output via a pipe */       perror("Failed to create starting pipe");       return 1;    }    if ((dup2(fd[0], STDIN_FILENO) == -1)         (dup2(fd[1], STDOUT_FILENO) == -1)) {       perror("Failed to connect pipe");       return 1;    }    if ((close(fd[0]) == -1)  (close(fd[1]) == -1)) {       perror("Failed to close extra descriptors");       return 1;    }    for (i = 1; i < nprocs;  i++) {         /* create the remaining processes */       if (pipe (fd) == -1) {          fprintf(stderr, "[%ld]:failed to create pipe %d: %s\n",                 (long)getpid(), i, strerror(errno));          return 1;       }       if ((childpid = fork()) == -1) {          fprintf(stderr, "[%ld]:failed to create child %d: %s\n",                  (long)getpid(), i, strerror(errno));          return 1;       }       if (childpid > 0)               /* for parent process, reassign stdout */           error = dup2(fd[1], STDOUT_FILENO);       else                              /* for child process, reassign stdin */           error = dup2(fd[0], STDIN_FILENO);       if (error == -1) {          fprintf(stderr, "[%ld]:failed to dup pipes for iteration %d: %s\n",                  (long)getpid(), i, strerror(errno));          return 1;       }       if ((close(fd[0]) == -1)  (close(fd[1]) == -1)) {          fprintf(stderr, "[%ld]:failed to close extra descriptors %d: %s\n",                 (long)getpid(), i, strerror(errno));          return 1;       }       if (childpid)          break;    }                                               /* say hello to the world */    fprintf(stderr, "This is process %d with ID %ld and parent id %ld\n",            i, (long)getpid(), (long)getppid());    return 0; } 
Team-FLY


Unix Systems Programming
UNIX Systems Programming: Communication, Concurrency and Threads
ISBN: 0130424110
EAN: 2147483647
Year: 2003
Pages: 274

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net